题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3342
题意:给出一个有向图,判断是否有环,也就是问是否是有向无环图(DAG),是则输出YES,否则输出NO,所以可以用是否存在拓扑序列来判断。
解题方案:用入度表的方法,即每次找入度为0的点,然后删掉这个点和由这个点发出的边,循环结束以后判断是不是每个点的入度都为0了,如果是则该DAG存在拓扑序列,否则说明存在环,则不存在拓扑序列。
解法一:入度数组+邻接表(vector 动态建表,建表时需要新建对象)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define FOR(i,k,n) for(int i=k;i<n;i++)
#define FORR(i,k,n) for(int i=k;i<=n;i++)
#define scan(a) scanf("%d",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mst(a,n) memset(a,n,sizeof(a))
#define ll long long
#define N 105
#define mod 1000000007
#define INF 0x3f3f3f3f
const double eps=1e-8;
const double pi=acos(-1.0);
int n,m;
int in[N];
vector<int> mp[N];
queue<int> q;
int solve()
{
while(!q.empty()) q.pop();
vector<int> v;
FOR(i,0,n) if(in[i]==0) v.push_back(i);
FOR(i,0,v.size())
{
q.push(v[i]);
while(!q.empty())
{
int cur=q.front();
q.pop();
FOR(j,0,mp[cur].size())
{
in[mp[cur][j]]--;
if(in[mp[cur][j]]==0) q.push(mp[cur][j]);
}
}
}
FOR(i,0,n)
if(in[i]) return 0;
return 1;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scann(n,m)&&n)
{
FOR(i,0,N) mp[i].clear();
mst(in,0);
FOR(i,0,m)
{
int u,v;
scann(u,v);
mp[u].push_back(v);//建邻接表时需动态新建对象
in[v]++;
}
//FOR(i,0,n) printf("%d ",in[i]);
int ans=solve();
if(ans) printf("YES\n");
else printf("NO\n");
}
return 0;
}
解法二:入度数组+邻接表(链式前向星 静态建表,采用静态数组,一次性内存申请),耗时和用vector一样都是31ms,并没有变快啊??是因为vector效率已经很高了?
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define FOR(i,k,n) for(int i=k;i<n;i++)
#define FORR(i,k,n) for(int i=k;i<=n;i++)
#define scan(a) scanf("%d",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mst(a,n) memset(a,n,sizeof(a))
#define ll long long
#define N 105
#define mod 1000000007
#define INF 0x3f3f3f3f
const double eps=1e-8;
const double pi=acos(-1.0);
int n,m;
int in[N];
queue<int> q;
struct Edge
{
int to;
//int w;
int next;
}E[N];
int head[N];//顶点i发出的输入数据中最后一条边的编号
int solve()
{
while(!q.empty()) q.pop();
vector<int> v;
FOR(i,0,n) if(in[i]==0) v.push_back(i);
FOR(i,0,v.size())
{
q.push(v[i]);
while(!q.empty())
{
int cur=q.front();
q.pop();
for(int j=head[cur];j!=-1;j=E[j].next)
{
int to=E[j].to;
in[to]--;
if(in[to]==0) q.push(to);
}
}
}
FOR(i,0,n)
if(in[i]) return 0;
return 1;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scann(n,m)&&n)
{
mst(E,0); mst(head,-1); mst(in,0);
FOR(i,0,m)
{
int u,v;
scann(u,v);
E[i].to=v;
E[i].next=head[u];
head[u]=i;
in[v]++;
}
//FOR(i,0,n) printf("%d ",in[i]);
int ans=solve();
if(ans) printf("YES\n");
else printf("NO\n");
}
return 0;
}