<a target=_blank href="http://acm.hdu.edu.cn/showproblem.php?pid=3342">http://acm.hdu.edu.cn/showproblem.php?pid=3342</a>
题意:给出一些人的名次关系,问存不存在冲突的情况。
分析: 这题其实就是判断拓扑排序的过程中是否会出现环。但是为是不能用并查集我现在还是想不通,如果有知道的可以告诉一声,感激不尽!!!!
PS: 重边 需要考虑...
下面有三种做法。
1.邻接表。
大概思想就是直接拓扑排序,然后用一个数组来保存每次排序的结果,如果最后数组的大小等于n表示排序成功,如果有环,数组大小肯定小于n。具体看代码。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define N 101
struct edges
{
int v;
int last;
}edge[N*N];
int cnt_edge;
int node[N];
int in[N],num[N];
int n,m,cnt;
queue<int>q;
void add_edge(int x,int y)
{
edge[cnt_edge].last=node[x];
edge[cnt_edge].v=y;
node[x]=cnt_edge++;
}
void clear()
{
cnt_edge=0;
cnt=0;
memset(num,0,sizeof(num));
memset(in,0,sizeof(in));
memset(node,-1,sizeof(node));
while(!q.empty()) q.pop();
}
int top_sort()
{
int now,next,j;
while(!q.empty())
{
now=q.front();
num[++cnt]=now;
q.pop();
for(j=node[now];j!=-1;j=edge[j].last)
{
next=edge[j].v;
in[next]--;
if(in[next]==0) q.push(next);
}
}
if(cnt==n) return 0;
else return 1;
}
int main()
{
while(scanf("%d%d",&n,&m),n+m)
{
clear();
int x,y;
while(m--)
{
scanf("%d%d",&x,&y);
add_edge(x,y);
in[y]++;
}
int i;
for(i=0;i<n;i++)
{
if(!in[i]) q.push(i);
}
if(top_sort()) printf("NO\n");
else printf("YES\n");
}
return 0;
}
2.邻接矩阵。 判断环的方法是: 在某一次排序的过程中找不到入度为 0 的点,即说明有环。实现可能比邻接表简单点。
#include<cstdio>
#include<cstring>
#define N 101
int map[N][N],in[N],n,flag;
int top_sort()
{
for(int i=0;i<n;i++)
{
flag=1;
for(int j=0;j<n;j++)
{
if(in[j]==0)
{
in[j]=-1; //删掉一条边
flag=0;
for(int k=0;k<n;k++)
if(map[j][k]) //与之相连的全部删除
in[k]--;
break;
}
}
if(flag) break;
}
return flag;
}
int main()
{
int m,i,j,k,x,y;
while(scanf("%d%d",&n,&m),n+m)
{
memset(map,0,sizeof(map));
memset(in,0,sizeof(in));
while(m--)
{
scanf("%d%d",&x,&y);
if(!map[x][y])
{
map[x][y]=1;
in[y]++;
}
}
if(top_sort()) printf("NO\n");
else printf("YES\n");
}
return 0;
}
3.floyed 时间用的蛮多, 就是用二维数组表示两点连通,floyed后,枚举自己跟自己如果连通,表示有环。
#include<cstdio>
#include<cstring>
#define N 101
int map[N][N],n,flag;
void floyed()
{
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
map[i][j]=map[i][j]||(map[i][k]&&map[k][j]);
for(int i=0;i<n;i++)
if(map[i][i]) {printf("NO\n"); return;}
printf("YES\n");
}
int main()
{
int m,i,j,k,x,y;
while(scanf("%d%d",&n,&m),n+m)
{
memset(map,0,sizeof(map));
while(m--)
{
scanf("%d%d",&x,&y);
map[x][y]=1;
}
floyed();
}
return 0;
}