csp 2020-9-13 第三题

题意:这道题大体就是给你一个组合电路,有输入信号和电器元件,他给你一些值然后让你输出询问的电器元件计算的值。

首先是输入:
第一行是q代表查询的次数,然后是m,n,分别是输入信号的数目和电器元件的数目。之后n行是电器元件作用(像AND,XOR等),然后是输入的信号的数目,后面是电器元件的符号(Ox)或者输入信号的符号(Ix)。然后是s代表运行的次数,之后是s行代表每次运行所有的输入信号的值(只有0和1两种)。之后s行每行第一个是要输出的电器元件的数目,之后是电器元件的序号(数字)。

然后是输出:
输出就是对最后s行每行查询的电器元件,输出他计算的值。(当然你还要判断是否有环路)

解题思路:
其实仔细一想这就是个拓扑排序。首先如果没有某个电器元件的输入量全是输入信号的,那么就一定存在环路,直接输出loop就行了。如果有的话,就可以设置电器元件的输入的其他电器元件的数目,存放在in数组里面(全是输入信号的话值为0,这个就是拓扑排序的起始点)。然后用队列直接实现拓扑排序就行了。
而在这里我用的结构体记录的电器元件和输入信号的信息。

上代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<vector>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
int in[100000]={0},q1,m,n,s;
vector<int> h[50005],g[50005];//这个是每次运行的所有信号量的值和你要输出的电器元件的信号
int in1[100000]={0},out1[100000]={0};//in1代表每次运行的(in代表的东西上面说了),out1就是我记录每个电器元件的计算的值
int flag;//flag=0代表有环路
struct node{
 string zt;
 int num;
 vector<int> u,v;
}e[100000];//结构体,zt是状态(如AND),num是计算的值,u是该电器元件的输入的信号或元件的序号,v是该元件是,,,的输入信号
int sol(string tt){//这个函数是将Ix和Ox转化成序号
 if(tt[0]=='I'){
  int tot=0;
  for(i/nt i=1;i<tt.size();i++){
   tot*=10;
   tot+=int(tt[i]-'0');
  }
  return tot;
 }else if(tt[0]=='O'){
  int tot=0;
  for(int i=1;i<tt.size();i++){
   tot*=10;
   tot+=int(tt[i]-'0');
  }
  tot+=m;
  return tot;
 }
}//在这里前m个是输入信号量,电器元件序号加m
void solve(int u){//这个是根据状态求计算的值
 if(e[u].zt=="NOT"){
  e[u].num=(!e[e[u].u[0]].num);
 }
 if(e[u].zt=="AND"){
  e[u].num=1;
  for(int i=0;i<e[u].u.size();i++)
  {
   e[u].num=(e[u].num&e[e[u].u[i]].num);
  }
 }
 if(e[u].zt=="OR"){
  e[u].num=0;
  for(int i=0;i<e[u].u.size();i++)
  {
   e[u].num=(e[u].num|e[e[u].u[i]].num);
  }
 }
 if(e[u].zt=="XOR"){
  e[u].num=0;
  for(int i=0;i<e[u].u.size();i++)
  {
   e[u].num=(e[u].num^e[e[u].u[i]].num);
  }
 }
 if(e[u].zt=="NAND"){
  e[u].num=1;
  for(int i=0;i<e[u].u.size();i++)
  {
   e[u].num=(e[u].num&e[e[u].u[i]].num);
  }
  e[u].num=(!e[u].num);
 }
 if(e[u].zt=="NOR"){
  e[u].num=0;
  for(int i=0;i<e[u].u.size();i++)
  {
   e[u].num=(e[u].num|e[e[u].u[i]].num);
  }
  e[u].num=(!e[u].num);
 }
}
void dfs(){//拓扑排序
 queue<int> q;
 for(int i=1;i<=m+n;i++){
  in1[i]=in[i];
 }
 for(int i=m+1;i<=m+n;i++){//这个是我上面说的判断环路
  if(in1[i]==0){
   q.push(i);
   flag=1;
  }
 }
 if(!flag)return;
 int hh=n;
 while(!q.empty()){
  int u=q.front();
  q.pop();
  solve(u);
  out1[u-m]=e[u].num;
  hh--;
  for(int i=0;i<e[u].v.size();i++){
   int cnt=e[u].v[i];
   in1[cnt]--;
   if(in1[cnt]==0){
    q.push(e[u].v[i]);
   }
  }
 }
 if(hh!=0){//如果依然存在电器元件没有更新,说明存在环路
  flag=0;
 }
}
int main()
{
 cin>>q1;
 while(q1--){
  flag=0;
  cin>>m>>n;
  for(int i=0;i<10000;i++){//这个是初始化
   h[i].clear();
   g[i].clear();
  }
  for(int i=1;i<=m+n;i++){
   in[i]=0;
  }
  for(int i=1;i<=m;i++){
   e[i].zt="0";
   e[i].num=-1;
   e[i].u.clear();
   e[i].v.clear();
  }
  for(int i=m+1;i<=m+n;i++){//对于每个信号或元件进行结构体构建
   e[i].num=0;
   e[i].u.clear();
   e[i].v.clear();
   string p;
   cin>>p;
   e[i].zt=p;
   int a1;
   cin>>a1;
   for(int j=0;j<a1;j++){
    string tt;
    cin>>tt;
    int num=sol(tt);
    e[i].u.push_back(num);
    if(num>m){
     in[i]++;
     e[num].v.push_back(i);
    }
   }
  }
  cin>>s;
  int w;
  for(int i=0;i<s;i++){//存储每次运行信号的值
   for(int j=0;j<m;j++){
    cin>>w;
    h[i].push_back(w);
   }
  }
  for(int i=0;i<s;i++){//要查询的信号
   int ww;
   cin>>ww;
   for(int j=0;j<ww;j++){
    cin>>w;
    g[i].push_back(w);
   }
  }
  for(int i=0;i<s;i++){
   memset(out1,0,sizeof(out1));
   memset(in1,0,sizeof(in1));
   for(int j=1;j<=m;j++){
    e[j].num=h[i][j-1];
   }
   dfs();
   if(!flag){//判断是否有环
    cout<<"LOOP"<<endl;
    break;
   }
   for(int j=0;j<g[i].size();j++){
    cout<<out1[g[i][j]]<<" ";//输出
   }
   cout<<endl;
  }
 }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值