新英雄
问题描述
老张也准备沉迷于lol不能自拔。为了表示自己的诚意,老张设计了一个新英雄。这个新英雄的大招非常强势,在追人的时候能体现非常强的优势。假设召唤师峡谷是一个有n个节点,m条单向边的图。对于每一个节点x,可以把所有以x为终点的边的权值减少d(-10000<=d<=10000),同时把所有以x为起点的边的权值加上d。要让所有边的权值的最小值最大。当然,边的权值不能为零或负,因为这不符合召唤师峡谷的物理规律。
输入格式
有多组数据,对于每一组数据:
第一行为两个整数n,m
接下来m行,每一行三个整数a,b,c 表示从a到b有一条长度为c的道路
输出格式
对于每一个数据块输出文件仅有一行:
如果答案有且仅有一个解,输出最短道路的最大可能值
如果答案具有任意性,即有多解,输出”Infinite”
如果无解,输出”No Solution”
样例输入
2 1
1 2 10
2 1
1 2 -10
3 3
1 2 4
2 3 2
3 1 5
4 5
2 3 4
4 2 5
3 4 2
3 1 0
1 2 -1
样例输出
Infinite
Infinite
3
1
数据规模
n≤500,m≤2700,-10000<=d<=10000每条道路的长度保证不超过10000
“最小值最大”,二分答案标志。显然,如果有解而且有有限解,那么答案一定在[1,10000]内。现在考虑如何验证答案。
设当前检验的答案为
ans
,在
p
号点操作的总权值为
移项后得到差分约束的标准形式:
所以如果当前答案都能满足所有这样的不等式,那就是合法的,反之就不是。也就是说,这样建图后,如果有负权回路就是不合法的,反之就是合法的。所以采用SPFA统计入队次数的方法。
那么什么情况下无解呢?如果原图中就有负环就无解。
什么情况下有多解呢?验证10001或更大的一个数,如果合法就说明有多解。
需要注意,每组数据先判断无解和无数组解的情况会比较好,特别是先判是否无解,因为如果无解,那么二分答案时,每次SPFA都要跑很多次使得入队次数达到 (N+1) 。
代码:
#include<stdio.h>
#include<cstring>
#define MAXN 505
#define MAXM 6005
using namespace std;
int N,M;
int en[MAXM],nex[MAXM],las[MAXN],len[MAXM],tot;
void Add(int x,int y,int z)
{
en[++tot]=y;
nex[tot]=las[x];
las[x]=tot;
len[tot]=z;
}
int Cnt[MAXN],Dis[MAXN];
bool mark[MAXN];
int Q[1000005],head,tail;
bool SPFA(int s,int k)
{
memset(Cnt,0,sizeof(Cnt));
memset(Dis,60,sizeof(Dis));
memset(mark,false,sizeof(mark));
Dis[0]=0;
head=1;
tail=0;
int i,x,y;
Q[++tail]=s;
while(head<=tail)
{
x=Q[head];head++;mark[x]=false;
for(i=las[x];i;i=nex[i])
{
y=en[i];
if(Dis[y]>Dis[x]+len[i]-k)
{
Dis[y]=Dis[x]+len[i]-k;
if(!mark[y])
{
mark[y]=true;
Cnt[y]++;
if(Cnt[y]>N)return false;
Q[++tail]=y;
}
}
}
}
return true;
}
void Init()
{
memset(las,0,sizeof(las));
tot=0;
}
int main()
{
int i,x,y,z;
while(scanf("%d%d",&N,&M)!=EOF)
{
Init();
for(i=1;i<=M;i++)
{
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z);
}
for(i=1;i<=N;i++)Add(0,i,0);
if(!SPFA(0,1))
{
puts("No Solution");
continue;
}
if(SPFA(0,10001))
{
puts("Infinite");
continue;
}
int L=1,R=10000,mid;
while(L<=R)
{
mid=L+R>>1;
if(SPFA(0,mid))L=mid+1;
else R=mid-1;
}
printf("%d\n",R);
}
}