A smile house is created to raise the mood. It has n rooms. Some of
the rooms are connected by doors. For each two rooms (number i and j),
which are connected by a door, Petya knows their value cij — the value
which is being added to his mood when he moves from room i to room j.Petya wondered whether he can raise his mood infinitely, moving along
some cycle? And if he can, then what minimum number of rooms he will
need to visit during one period of a cycle?Input The first line contains two positive integers n and m (), where
n is the number of rooms, and m is the number of doors in the Smile
House. Then follows the description of the doors: m lines each
containing four integers i, j, cij и cji
(1 ≤ i, j ≤ n, i ≠ j, - 104 ≤ cij, cji ≤ 104). It is guaranteed that
no more than one door connects any two rooms. No door connects the
room with itself.Output Print the minimum number of rooms that one needs to visit
during one traverse of the cycle that can raise mood infinitely. If
such cycle does not exist, print number 0.
在两个限制条件中,一个【权值和为正】是硬性条件,但是我们在求解中需要尽量保证局部最优才能使后面选择余地较大,另一个【边数最少】是要求最优化的答案。两个都要求尽量优是容易顾此失彼的,但是如果我们认为可以在原地停留,也就是把最优值定义为不超过k步的结果,可以推得f[k][i][j]表示至少走k步,从i点到j点,路上的最大权值和,这样的话答案就具有了关于k的单调性,我们可以二分答案之后贪心的选取权值。
但是这样的话复杂度是O(n^4logn),无法承受。因为有许多重复运算,可以用倍增优化,复杂度O(n^3(logn)^2)。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int oo=0x3f3f3f3f;
int f[10][310][310],ans[2][310][310],n;
bool ok(int x)
{
int k,now=0,i,j,p;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
ans[0][i][j]=i==j?0:-oo;
for (k=0;(1<<k)<=x;k++)
if (x&(1<<k))
{
now^=1;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
ans[now][i][j]=-oo;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
for (p=1;p<=n;p++)
ans[now][i][j]=max(ans[now][i][j],ans[now^1][i][p]+f[k][p][j]);
}
for (i=1;i<=n;i++)
if (ans[now][i][i]>0) return 1;
return 0;
}
int main()
{
int i,j,k,m,p,q,x,y,z,w,l,r,mid;
scanf("%d%d",&n,&m);
for (k=0;(1<<k)<=n;k++)
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
f[k][i][j]=i==j?0:-oo;
for (i=1;i<=m;i++)
{
scanf("%d%d%d%d",&x,&y,&z,&w);
f[0][x][y]=z;
f[0][y][x]=w;
}
for (k=1;(1<<k)<=n;k++)
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
for (x=1;x<=n;x++)
f[k][i][j]=max(f[k][i][j],f[k-1][i][x]+f[k-1][x][j]);
l=2;
r=n+1;
while (l<r)
{
mid=(l+r)/2;
if (ok(mid)) r=mid;
else l=mid+1;
}
printf("%d\n",l%(n+1));
}