题意:有n个城市,任意两点之间有且仅有一条有向边。要求输出一种建造城市的顺序,使得之前已经建造的城市可以到达当前建造的城市,且至多经过两条边。
首先我们可以证明,这种方案是肯定存在的,
因为在一个满足题意的图中,入度最大的点一定是其他点在两步之内可达的。那么这个点就最后输出。
上面的结论是为什么呢。。题解告诉我们用反证法证明,
若u结点是当前图中入度最大的结点,假设v点存在该路径v->a->b->u,
由于u是入度最大的结点,那么v 不可能连到u以及 b或者与u直接相连的点(不然v就可以两步到达u了),
由于两点间有一条有向边,v连布到他们,那么他们到v一定有边,既v的入度至少是 u+指向u的点,既v的入度大于u的,这里矛盾了。
所以我们可以知道,在任何一个符合题意的图中,都可以知道最后输出的点,
我们每找到一个点,就标记,把与该点相连的边删去。这样找完了倒序输出就i可以了。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#define inf 0x3f3f3f3f
#pragma comment(linker, "/STACK:16777216")
#define eps 1e-6
#define ll long long
using namespace std;
const int maxn=505;
int n,in[maxn],vis[maxn];
char s[maxn][maxn];
int main()
{
int i,j;
while(~scanf("%d",&n)&&n)
{
memset(in,0,sizeof in);
for(i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
for(j=1;j<=n;j++)
if(s[i][j]=='1')
in[j]++;
}
vector<int> ans;
memset(vis,0,sizeof vis);
int maxin,p,flag=1;
while(flag)
{
flag=0,maxin=-1,p=0;
for(i=1;i<=n;i++)
{
if(!vis[i]&&maxin<in[i])
{
flag=1;
maxin=in[i];
p=i;
}
}
if(flag)
{
vis[p]=1;
ans.push_back(p);
for(i=1;i<=n;i++)
{
if(i==p) continue;
if(s[p][i]=='1') in[i]--;
}
}
}
printf("%d",ans[ans.size()-1]);
for(i=ans.size()-2;i>=0;i--)
printf(" %d",ans[i]);
puts("");
}
return 0;
}
/*
4
0111
0011
0001
0000
4
0100
0010
1001
1100
1 2 3 4
3 4 1 2
*/