寒假第五次训练-欧拉回路&拓扑排序
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 505
int 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 10005
int 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 1005
int 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 100005
int 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");
}
}