太巧妙了!!
关键1:把开着的灯当成黑点看待
关键二:如图
更多细节请看代码
code
#include<bits/stdc++.h>
using namespace std;
int to[100005];//代表会被我影响的灯,抽象成边
void solve()
{
int n;
int state[100005]={0};//代表每个灯的状态
int ind[100005]={0};//代表入度
string s;
cin>>n>>s;
vector<int> ans;//代表答案,需要关掉灯的编号
for(int i=1;i<=n;i++)
{
cin>>to[i];
ind[to[i]]++;
if(s[i-1]=='1')state[i]=1;//用数组代替,方便计算
}
queue<int> q;
for(int i=1;i<=n;i++) if(!ind[i]) q.push(i);//从入度为零的点开始消除,即消除链
while(q.size())
{
int now=q.front();
q.pop();
if(--ind[to[now]]==0)q.push(to[now]);
if(state[now])//把开着的灯想象成黑色的点,开关后,黑点会向下移动,且黑点遇到黑点时会消除
{
ans.push_back(now);
state[to[now]]^=1;
state[now]=0;
}
}
for(int i=1;i<=n;i++)
{
if(ind[i])//现在把链全部去掉了,环可能有多个
{
int x=i,len=0,half=0,curstate=0;
while(ind[x]--)
{
curstate^=state[x];
half+=curstate;
len++;
x=to[x];
}
if(curstate)
{
cout<<"-1"<<endl;//如果环上的黑点奇数个,肯定无法消除
return;
}
for(int i=1;i<=len;i++)//这一段判断环上需要关掉灯的方法太巧妙了!!
{
curstate^=state[x];
if(curstate==(2*half<=len))ans.push_back(x);
x=to[x];
}
}
}
cout<<ans.size()<<endl;
for(int i:ans)cout<<i<<" ";
cout<<endl;
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--) solve();
return 0;
}
标签:int,100005,Lights,state,solve,ind
From: https://www.cnblogs.com/pure4knowledge/p/17970142