新英雄
問題描述
老張也準備沉迷於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]內。現在考慮如何驗證答案。
設當前檢驗的答案爲
移項後得到差分約束的標準形式:
所以如果當前答案都能滿足所有這樣的不等式,那就是合法的,反之就不是。也就是說,這樣建圖後,如果有負權迴路就是不合法的,反之就是合法的。所以採用SPFA統計入隊次數的方法。
那麼什麼情況下無解呢?如果原圖中就有負環就無解。
什麼情況下有多解呢?驗證10001或更大的一個數,如果合法就說明有多解。
需要注意,每組數據先判斷無解和無數組解的情況會比較好,特別是先判是否無解,因爲如果無解,那麼二分答案時,每次SPFA都要跑很多次使得入隊次數達到
代碼:
#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);
}
}