#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=101;
const int maxm=3003;
const int INF=0x3fffffff;
int n,m;
int e[maxn][maxn],vis[maxn],pre[maxn][maxn],dis[maxn],flag,f[maxn],a[maxm],b[maxm];
int bfs(int x)
{
int i,j,k,u,ans=0;
queue<int>q;
memset(vis,0,sizeof(vis));
vis[x]=1;
dis[x]=0;
q.push(x);
while(!q.empty())
{
u=q.front();
q.pop();
for(i=1;i<=n;i++)
{
if(vis[i]||!e[u][i])continue;
dis[i]=dis[u]+1;
vis[i]=1;
if(!flag)
pre[x][i]=u;
q.push(i);
}
}
for(i=x+1;i<=n;i++)
{
if(!vis[i])return INF;
ans+=dis[i];
}
return ans;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int i,j,k,sum=0,ans=0,t;
memset(e,0,sizeof(e));
flag=0;
for(i=0;i<m;i++)
{
scanf("%d%d",&a[i],&b[i]);
e[a[i]][b[i]]++;
e[b[i]][a[i]]++;
}
for(i=1;i<=n;i++)
{
f[i]=bfs(i);
if(f[i]==INF)break;
}
if(i<=n){printf("INF\n");continue;}
flag=1;
for(i=0;i<m;i++)
{
ans=0;
e[a[i]][b[i]]--;
e[b[i]][a[i]]--;
for(j=1;j<=n;j++)
{
if(pre[j][a[i]]!=b[i]&&pre[j][b[i]]!=a[i]){ans+=f[j];continue;}//剪枝
t=bfs(j);
if(t==INF)break;
ans+=t;
}
e[a[i]][b[i]]++;
e[b[i]][a[i]]++;
if(j<=n)printf("INF\n");
else printf("%d\n",2*ans);
}
}
return 0;
}
/*
bfs+剪枝,1750MS/2000MS,时间真卡啊
pre[i][j]表示从i到j的最短路径上j的前一个点。用于剪枝,如果删去的点正好是pre[i][j]和j,
那么i和j之间的最短路改变,否则不变。
这题除了上面的剪枝,还要注意两点之间可以有多条边。。
f[i]记录的是i和比i大的结点的最短路和。
*/
hdu 2433 Travel bfs+剪枝
最新推荐文章于 2021-10-31 14:15:53 发布