寒假第五次训练-欧拉回路&拓扑排序
A - 确定比赛名次
题目大意:有n支队伍比赛,已知m组形如:a b的数据,表示a战胜了b,求所有队伍的排名顺序,且序号小的队伍排名在前
解题思路:拓扑排序,需要注意的是在每搜索到一个入度为0的点且削减完与它连接的点的入度就重新循环,保证序号小的在前。
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <stack>using namespace std;#define MAXN 505int indegree[MAXN],topo[MAXN],n,m;int G[MAXN][MAXN];void toposort(){ int u,v,i,t=0; memset(topo,0,sizeof(topo)); for (i=0; i<n; i++) { for (u=1; u<=n; u++) { if (indegree[u]==0) { indegree[u]=-1; topo[t++]=u; for (v=1; v<=n; v++) { if (G[u][v]) indegree[v]--; } break; } } }}int main(){ int u,v; while(~scanf("%d%d",&n,&m)) { memset(G,0,sizeof(G)); memset(indegree,0,sizeof(indegree)); for (int i=0; i<m; i++) { scanf("%d%d",&u,&v); if (G[u][v]==0) { G[u][v]=1; indegree[v]++; } } toposort(); for (int i=0; i<n; i++) printf("%d%c",topo[i],i==n-1?'\n':' '); }}
B - Reward
题目大意:有n个工人,他们需要从老板那里拿工资,然后提出了m个要求,形如:a b,表示a要求工资比b高,每个人基准工资为888,求老板需支出的最小工资
解题思路:数据较大,用邻接表(vector)存储,a比b工资高则a的入度增加,从入度为0的基准工资(888)开始拓扑排序,最后加和。
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <stack>using namespace std;#define MAXN 10005int indegree[MAXN],a[MAXN],n,m;vector<int> G[MAXN];stack<int> temp;void toposort(){ int u,v,i,t=0,rec=n,sum=0; memset(a,0,sizeof(a)); for (i=0; i<n; i++) { for (u=1; u<=n; u++) { if (indegree[u]==0) { temp.push(u); indegree[u]=-1; a[u]=i; rec--; } } while (!temp.empty()) { u=temp.top(); temp.pop(); for (v=0; v<G[u].size(); v++) { indegree[G[u][v]]--; } } } if (rec==0) { for (int i=1;i<=n;i++) sum+=a[i]; printf("%d\n",888*n+sum); } else { printf("-1\n"); }}int main(){ int u,v; while(~scanf("%d%d",&n,&m)) { memset(indegree,0,sizeof(indegree)); for (int i=0; i<=n; i++) G[i].clear(); for (int i=0; i<m; i++) { scanf("%d%d",&u,&v);//v比u工资低 G[v].push_back(u); indegree[u]++; } toposort(); }}
D - 欧拉回路
题目大意:欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?
解题思路:欧拉回路要满足:1.图是联通的;2.每个点连线数为偶数
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <stack>using namespace std;#define MAXN 1005int degree[MAXN],n,m;int G[MAXN][MAXN];bool judge(){ int i,j; for (i=1; i<=n; i++) { if (degree[i]%2!=0) return false; for (j=1; j<=n; j++) { if (i!=j && G[i][j]!=1) return false; } } return true;}int main(){ int u,v; while(scanf("%d",&n),n) { scanf("%d",&m); memset(G,0,sizeof(G)); memset(degree,0,sizeof(degree)); for (int i=0; i<m; i++) { scanf("%d%d",&u,&v); if (G[u][v]==0) { G[v][u]=G[u][v]=1; degree[v]++; degree[u]++; } } if (judge()) printf("1\n"); else printf("0\n"); }}
E - Play on Words
题目大意:给定n个单词,判断是否可以适当排序使之首尾相连,如:acm与mouse就可以连接
解题思路:单词的首尾字母作为节点,中间部分作为连线,划为欧拉道路问题来解决,用并查集判断是否联通
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <stack>using namespace std;#define MAXN 100005int indegree[27],outdegree[27],n;int count_;int par[27],rank_[27];bool hash_[27];void init(){ int i; for (i=0;i<26;i++) par[i]=i; rank_[i]=0;}int find_(int x){ if (par[x]==x) return x; else return par[x]=find_(par[x]);}void unite(int x,int y){ x=find_(x); y=find_(y); if (x==y) return; if (rank_[x]<rank_[y]) par[x]=y; else { par[y]=x; if (rank_[x]==rank_[y]) rank_[x]++; } count_--;}bool judge(){ int i,j,rec=0,flag1=0,flag2=0; for (i=0;i<26;i++) { if (indegree[i]!=outdegree[i]) { rec++; if (rec>2) return false; if (indegree[i]==outdegree[i]+1) flag1=1; else if (indegree[i]==outdegree[i]-1) flag2=1; else return false; } } if (count_!=1) return false; if (rec==0 || (rec==2 && flag1&flag2)) return true; else return false; return true;}int main(){ int u,v,t,j; int first,last; char word[1005]; scanf("%d",&t); while(t--) { scanf("%d",&n); count_=0; memset(indegree,0,sizeof(indegree)); memset(outdegree,0,sizeof(outdegree)); memset(hash_,true,sizeof(hash_)); init(); for (int i=0; i<n; i++) { scanf("%s",word); first=word[0]-97; for(j=0;word[j]!='\0';j++); last=word[j-1]-97; outdegree[first]++; indegree[last]++; if (hash_[first]) { hash_[first]=false; count_++; } if (hash_[last]) { hash_[last]=false; count_++; } unite(first,last); } if (judge()) printf("Ordering is possible.\n"); else printf("The door cannot be opened.\n"); }}