Harry and Magical Computer
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 249 Accepted Submission(s): 118
Problem Description
In reward of being yearly outstanding magic student, Harry gets a magical computer. When the computer begins to deal with a process, it will work until the ending of the processes. One day the computer got n processes to deal with. We number the processes from 1 to n. However there are some dependencies between some processes. When there exists a dependencies (a, b), it means process b must be finished before process a. By knowing all the m dependencies, Harry wants to know if the computer can finish all the n processes.
Input
There are several test cases, you should process to the end of file.
For each test case, there are two numbers n m on the first line, indicates the number processes and the number of dependencies.
1≤n≤100,1≤m≤10000
The next following m lines, each line contains two numbers a b, indicates a dependencies (a, b).
1≤a,b≤n
Output
Output one line for each test case.
If the computer can finish all the process print "YES" (Without quotes).
Else print "NO" (Without quotes).
Sample Input
3 2
3 1
2 1
3 3
3 2
2 1
1 3
Sample Output
Source
BestCoder Round #25
题意:
有一台电脑只能做一个任务直到结束才能做另外一个任务. 现有一种约束条件是(v,u) : 在做v任务前必须做u任务. 先在给你一个n和m,
n表示共有n个任务,
m表示共有m个约束条件,问这台电脑是否能完成n个任务;
方法1:
利用邻接矩阵建立一个有向图,看这个有向图是否会形成环. 用最短路floyd算法, 如果邻接矩阵的主对角线有1,则说明有环.
code_1:
/*************************************************************************
> File Name: topo.cpp
> Author: tj
> Mail: [email protected]
> Created Time: 2015年01月04日 星期日 11时01分24秒
************************************************************************/
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int main()
{
int n, m, u, v, dp[110][110];
while(~scanf("%d%d", &n,&m))
{
memset(dp, 0, sizeof(dp));
for(int i=1; i<=m; i++)
{
scanf("%d%d", &v,&u);
dp[u][v] = 1;
}
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
dp[i][j] = max(dp[i][j], dp[i][k]&dp[k][j]);
int flag = 0;
for(int i=1; i<=n; i++)
if(dp[i][i] == 1) flag = 1;
printf(!flag ? "YES\n" : "NO\n");
}
return 0;
}
方法二: (错了。。请忽略。。。)
利用类似并查集的方法,用p[v]数组来存储v的父亲,然后每次都要查询一下父亲的父类中是否会有等于儿子的情况. 如果有,则说明会形成环.
code_2:
/*************************************************************************
> File Name: union-find.cpp
> Author: tj
> Mail: [email protected]
> Created Time: 2015年01月04日 星期日 13时21分08秒
************************************************************************/
#include<stdio.h>
#include<iostream>
using namespace std;
int p[110];
bool find(int x, int val)
{
if(p[x] == val) return 1; //如果x的父亲是val则存在环
if(p[x] == x) return 0; //找到根结点就不用继续找了
find(p[x], val); //继续查找父类
}
int main()
{
int n, m, u, v;
while(~scanf("%d%d", &n,&m))
{
for(int i=1; i<=n; i++) p[i] = i; //初始化父类
int flag = 0;
for(int i=1; i<=m; i++)
{
scanf("%d%d", &v,&u);
if(find(u,v)) flag = 1; //如果查到v也是u的父类,则有环
else p[v] = u; //u是v的父亲
}
printf(!flag ? "YES\n" : "NO\n");
}
return 0;
}
一个结点有可能有多个父结点,也就是说会指向多个点,这样并查集中那个点的指向会被覆盖,所以这样做是错误的,只是此题数据水让我过了。。
附测试数据:
4 4
2 3
3 1
3 4
1 2