uva10305
题意很简单,给你几个任务,这几个任务之间有先做和后做的顺序,如果a,b之间有顺序的话,就必须在做b之前先把a做了,然后问你做这几件事的一个可能的顺序是什么(答案可能不唯一,只要满足要求即可)。
这道题很基础的一道拓扑排序,由于数据很小,可以采用矩阵来存储图;关于拓扑排序网上也有很多讲解,感觉dfs这种比较容易理解一点吧,在《算法竞赛入门经典》第二版167页讲解有;
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#define INF 0x3f3f3f3f
#define N 200
using namespace std;
int G[N][N];
int c[N],top[N],t,n;
bool dfs(int u)
{
c[u]=-1;//c[u]=0表示该点没被访问过,c[u]=-1表示正在访问,c[u]=1表示已经访问过;
int i;
for(i=1; i<=n; i++)
{
if(G[u][i])
{
if(c[i]<0)//如果正在访问的点它的后继为-1的话说明该点再次出现了,代表有环,失败退出;
return false;
else if(!c[i]&&!dfs(i))//如果正在访问的点它的后继中某个点在求dfs时,dfs为假,则说明正在访问的点它的后继中某个点再次出现了,则后继中有环,失败退出
return false;
}
}
c[u]=1;
top[t--]=u;//由于是递归调用,所以应当倒着存储;
return true;
}
bool topsort()
{
int i;
t=n;
memset(c,0,sizeof(c));
for(i=1; i<=n; i++)
if(!c[i])
{
if(!dfs(i))
return false;
}
return true;
}
int main()
{
int m,i,a,b;
while(1)
{
scanf("%d%d",&n,&m);
if(m==0&&n==0)
break;
memset(G,0,sizeof(G));
for(i=1; i<=m; i++)
{
scanf("%d%d",&a,&b);
G[a][b]=1;
}
topsort();
for(i=1; i<=n; i++)
printf("%d%c",top[i],i==n?'\n':' ');
}
return 0;
}
上面的方法是用邻接矩阵的方法存储的,但是当数据量过大的时候用矩阵存储肯定会爆内存的,这时候就可以用STL中容器来存储;
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#define INF 0x3f3f3f3f
#define N 200
using namespace std;
int c[N],top[N],t,n;
vector<int>G[N];//用容器存储邻接表
bool dfs(int u)
{
c[u]=-1;
int i;
for(i=0; i<G[u].size(); i++)
{
if(c[G[u][i]]<0)
return false;
else if(!c[G[u][i]]&&!dfs(G[u][i]))
return false;
}
c[u]=1;
top[t--]=u;
return true;
}
bool topsort()
{
int i;
t=n;
memset(c,0,sizeof(c));
for(i=1; i<=n; i++)
if(!c[i])
{
if(!dfs(i))
return false;
}
return true;
}
int main()
{
int m,i,a,b;
while(1)
{
scanf("%d%d",&n,&m);
if(m==0&&n==0)
break;
for(i=0;i<=n;i++)
G[i].clear();
for(i=1; i<=m; i++)
{
scanf("%d%d",&a,&b);
G[a].push_back(b);
}
topsort();
for(i=1; i<=n; i++)
printf("%d%c",top[i],i==n?'\n':' ');
}
return 0;
}
这样一来即使数据过大也不会爆内存了;
lightoj 1003
这道题也是个拓扑排序,只需要用map转化一下数字就行了,不过这道题数据过大,用邻接矩阵存储会爆内存,这时候就可以用上面说的用容器实现邻接表的存储了;
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#define INF 0x3f3f3f3f
#define N 20010
using namespace std;
int c[N],top[N],t,n;
map<string,int>mp;
vector<int>G[N];
int str(string s)//利用map实现由字符串到数字的转化
{
if(!mp[s])
{
mp[s]=++n;
return n;
}
return mp[s];
}
bool dfs(int u)
{
c[u]=-1;
int k=G[u].size();
for(int i=0; i<k; i++)
{
if(c[G[u][i]]<0)
return false;
else if(!c[G[u][i]]&&!dfs(G[u][i]))
return false;
}
c[u]=1;
top[--t]=u;
return true;
}
bool topsort()
{
int i;
t=n;
memset(c,0,sizeof(c));
for(i=1; i<=n; i++)
if(!c[i])
{
if(!dfs(i))
return false;
}
return true;
}
int main()
{
int T,i,m,a,b;
string s1,s2;
int k=0;
scanf("%d",&T);
while(T--)
{
scanf("%d",&m);
n=0;
mp.clear();
for(i=0; i<=m*2; i++)//记得清空,是2*m的大小
G[i].clear();
for(i=0; i<m; i++)
{
cin>>s1>>s2;
a=str(s1);
b=str(s2);
G[a].push_back(b);
}
if(topsort())
printf("Case %d: Yes\n",++k);
else
printf("Case %d: No\n",++k);
}
return 0;
}