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");//两个换行
	}
}
posted @ 2021-09-07 19:58  AFewSuns  阅读(41)  评论(0编辑  收藏  举报