P16586 [GKS 2016 #C] Evaluation 题解
题目大意
给你 \(N\) 条赋值语句,每条语句表示一个变量能被赋值当且仅当函数内的所有变量均被赋值,如果函数内一个变量都没有,那么可以直接赋值,每个变量都是长度不超过 \(20\) 的字符串。
没有变量会作为赋值变量出现多次,但变量可以在不同函数中(甚至同一函数内)出现多次,而且如果一个变量同时是赋值变量且在函数里,那么它将不能被赋值。
最后问有没有一种顺序使得所有变量均能被赋值。
算法分析
显然是一道拓扑排序题。所以首先,对于所有赋值语句,把对应的函数内的变量和赋值变量连边,然后判断有没有自环或环或有出现的变量无法被赋值,有就答案为否,否则就跑一边拓扑排序,最后再看有没有点入读不为 \(0\),有就答案为否,否则答案为是。
::::info[代码]
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;//记得开大一点,因为每条函数最多有10个变量
map<string,int> mp;
vector<int> G[N];
int a[N],rd[N],cnt,uns;
int getname(string s){//把字符串打个编号
if(!mp[s]){//如果没出现过
mp[s]=++uns;
}
return mp[s];
}
queue<int> q;
void init(){//清空数组
while(q.size())q.pop();
memset(a,0,sizeof a);
memset(rd,0,sizeof rd);
mp.clear();
for(int i=1;i<=uns;i++){
G[i].clear();
}
uns=cnt=0;
}
void work(){
int m;
cin>>m;
while(m--){
map<int,int> mpp;
string s;
cin>>s;
int cz=1,mb=0;
string t="";
int f=0;
for(int i=0;i<s.size();i++){
if(cz==1){//先把赋值变量抓出来
if(s[i]=='='){
mb=getname(t);
t="";
cz=2;
continue;
}
t+=s[i];
}else if(cz==2){//然后把函数里的变量抓出来
if(s[i]=='('){
cz=3;
continue;
}
}else{
if(s[i]==')'&&t==""){//这里是可以直接赋值的变量
a[++cnt]=mb;
continue;
}
if(s[i]==')'||s[i]==','){//不然就是会被依赖的变量
int name=getname(t);
t="";
if(mpp[name]){//这里要判断是否已经出现过了,重复的没有意义
continue;
}
rd[mb]++;
if(name==mb){//自环
f++;
continue;
}
mpp[name]=1;
G[name].push_back(mb);
}else{
t+=s[i];
}
}
}
if(f){//如果有自环,答案肯定为否
cout<<"BAD";
return;
}
}
for(int i=1;i<=cnt;i++){
q.push(a[i]);//把可以直接赋值的变量放进去
}
while(q.size()){//拓扑排序
int d=q.front();
q.pop();
for(int i=0;i<G[d].size();i++){
int v=G[d][i];
rd[v]--;
if(!rd[v]){
q.push(v);
}
}
}
for(int i=1;i<=uns;i++){
if(rd[i]){
cout<<"BAD";
return;
}
}
cout<<"GOOD";
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T,id=0;
cin>>T;
while(T--){
cout<<"Case #"<<++id<<": ";
init();
work();
cout<<'\n';
}
return 0;
}
::::

浙公网安备 33010602011771号