题外: 这个题思路挺好想的,但是我命令序列的数组没开够卡了好久,, 所以这是小于kmax还是小于N呢,,我一直以为是kmax。。好吧我的锅
思路: 每个器件之间存在先后关系,比如1的输出是2的输入,那么必须先算1再算2,所以建个图找出拓扑序然后按着拓扑序计算各个值就可以了。整体来说没有什么坑点。
代码:
#include <cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int N = 10005;
int fun[510],res[510],d[510],order[510],topo[510];
int e[N],ne[N],h[N];
int idx;
int seq[N][505]; //命令序列,,就是卡在了这,吐血
int getid(string s)
{
int ans=0;
for(int i=1;i<s.size();i++)
ans=ans*10+s[i]-'0';
return ans;
}
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool isloop(int n)
{
queue<int> q;
for(int i=1;i<=n;i++)
if(!d[i])
q.push(i);
int num=0;
while(q.size())
{
int x=q.front();
q.pop();
topo[num++]=x;
for(int i=h[x];i;i=ne[i])
{
int j=e[i];
d[j]--;
if(d[j]==0)
q.push(j);
}
}
return !(num==n);
}
void cal(int x,vector<int> &v)
{
int ans=res[v[0]];
switch(fun[x])
{
case 1:
ans=!ans;
break;
case 2:
for(int i=1;i<v.size();i++)
ans=ans&res[v[i]];
break;
case 3:
for(int i=1;i<v.size();i++)
ans=ans|res[v[i]];
break;
case 4:
for(int i=1;i<v.size();i++)
ans=ans^res[v[i]];
break;
case 5:
for(int i=1;i<v.size();i++)
ans=ans&res[v[i]];
ans=!ans;
break;
case 6:
for(int i=1;i<v.size();i++)
ans=ans|res[v[i]];
ans=!ans;
break;
}
res[x]=ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
map<string,int> mp; //初始化
mp["NOT"]=1;
mp["AND"]=2;
mp["OR"]=3;
mp["XOR"]=4;
mp["NAND"]=5;
mp["NOR"]=6;
int q;
cin>>q;
while(q--)
{
idx=1;
int n,m;
cin>>m>>n;
vector<int> v[n+1]; //存储输入端有哪些
for(int i=0;i<6*n+1;i++)
h[i]=0;
memset(d,0,sizeof d);
for(int i=1;i<=n;i++)
{
string s;
int k;
cin>>s>>k;
fun[i]=mp[s];
for(int j=0;j<k;j++)
{
cin>>s;
int id=getid(s);
d[i]++;
//把开始的m个输入信号也看做特殊器件,从n+1 ~ n+m编号
if(s[0]=='I')
add(n+id,i),v[i].push_back(id+n);
else
add(id,i),v[i].push_back(id);
}
}
int s;
cin>>s;
for(int i=0;i<s;i++)
for(int j=0;j<m;j++)
cin>>seq[i][j];
int flag=isloop(n+m);
for(int r=0;r<s;r++)
{
int num;
cin>>num;
for(int i=0;i<num;i++)
cin>>order[i];
if(flag)
continue;
for(int i=n+1;i<=n+m;i++)
res[i]=seq[r][i-n-1];
for(int i=0;i<n+m;i++)
if(topo[i]<=n)
cal(topo[i],v[topo[i]]);
for(int i=0;i<num;i++)
{
if(i) cout<<" ";
cout<<res[order[i]];
}
cout<<endl;
}
if(flag)
cout<<"LOOP"<<endl;
}
return 0;
}