UVA11060 Beverages
题意简述
Dilbert 喜欢喝饮料(酒)。有多组数据,每组数据会给你 \(n\) 个饮料的名字,和 \(m\) 个饮料之间的关系。对于关系 \(B_1\ B_2\),意思是喝 \(B_2\) 之前必须先喝 \(B_1\)(关系之间具有传递性)。求 Dilbert 喝饮料的顺序。
\(1 \leq n \leq 100\ ,\ 0 \leq m \leq 200\)
题目分析
考虑到数据范围极小,直接上暴力。
对于一个饮料 \(B\),它有很多个“前提”,也就是说必须喝完这些“前提”的饮料才能喝它。于是记录一下每个饮料的“前提”个数 \(cnt_i\),每次找到一个 \(cnt_i=0\) 的饮料,喝完它并且将与它有关系的饮料的 \(cnt\) 减一(即它是哪些饮料的“前提”)。其实这相当于一个有向图,每个关系都是一条有向边,最后对它进行拓扑排序。
注意:
-
如果有多个 \(cnt_i\) 为 \(0\) 的饮料,则优先选择输入顺序较前的饮料
-
喝完一个饮料后可能会有新的饮料 \(cnt\) 变为 \(0\),为了遵照上面的顺序需要重头再枚举一遍
-
输出有特定的格式:注意中英文符号,有无空格,最后一个饮料后面应该紧跟着 “.”,每个数据输出完毕后应该有2个换行,即中间多空一行(这东西让我调了好久)
-
清空数组,名字用 map 存就好啦
代码
#include<bits/stdc++.h>
using namespace std;
namespace my_std{
#define ll long long
#define pf printf
#define pc putchar
#define fr(i,x,y) for(register ll i=(x);i<=(y);i++)
#define space pc(' ')
#define il inline
il ll read(){
ll sum=0,f=1;
char ch=0;
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
sum=sum*10+(ch^48);
ch=getchar();
}
return sum*f;
}
}
using namespace my_std;
vector<ll> v[101];//存这个饮料是谁的 “前提 ”
map<string,ll> mp;//名字对应到数字
map<ll,string> nam;//数字对应到名字
ll n,m,cnt=0,in[101],tot=0,cntt=0;
string s;
int main(){
while(scanf("%lld",&n)!=EOF){
tot++;
cntt=0;
mp.clear();
nam.clear();
cnt=0;//多测清空
fr(i,1,n){
in[i]=0;
string s;
cin>>s;
if(!mp[s]){
mp[s]=++cnt;
nam[cnt]=s;//记录名字
}
}
fr(i,1,n) v[i].clear();
m=read();
fr(i,1,m){
ll x,y;
cin>>s;
x=mp[s];
cin>>s;
y=mp[s];
v[x].push_back(y);
in[y]++;// in 数组即前面的 cnt 数组
}
pf("Case #%lld: Dilbert should drink beverages in this order: ",tot);
fr(t,1,n){
fr(i,1,n){
if(!in[i]){
cntt++;
in[i]--;
cout<<nam[i];
if(cntt<n) space;//最后一个饮料后面没有空格
for(ll j=0;j<v[i].size();j++) in[v[i][j]]--;
break;//从头枚举
}
}
}
pf(".\n\n");//两个换行
}
}