题目大意:
给你一个N个点,M条边的有向图G,每一条边有两个属性:cost,time。然后要你求出一个环T使得
解题思路:
我们要求最大值,一个很直观的思路就是二分答案,然后那么题目就变为询问是否存在一个环T使得使得
整理有:
易发现这就是spfa判负环的条件,然后就很简单了吧!!!
AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
struct bian_
{
int num;
double cost,times;
int next;
}bian[10000]={{0,0,0,0}};
int First[52]={0};
int n,m;
int father[52]={0};
double dist[52]={0};
int hash[52]={0};
int Times[52]={0};
inline void Add(int p,int q,double u,double v,int k)
{
bian[k].next=First[p];
bian[k].num=q;
bian[k].cost=u;
bian[k].times=v;
First[p]=k;
return;
}
inline int check(double k)
{
queue <int> Queue;
for(;!Queue.empty();) Queue.pop();
for(int i=1;i<=n;i++)
dist[i]=1e9;
dist[1]=0;
Queue.push(1);
memset(hash,0,sizeof(hash));
hash[1]=1;
memset(father,0,sizeof(father));
memset(Times,0,sizeof(Times));
Times[1]++;
for(;!Queue.empty();)
{
int u=Queue.front();
Queue.pop();
if(Times[u]>n+1)
return u;
for(int p=First[u];p!=0;p=bian[p].next)
{
int v=bian[p].num;
double d=(double)bian[p].times*k-bian[p].cost;
if(dist[u]+d<dist[v])
{
father[v]=u;
dist[v]=dist[u]+d;
if(hash[v]==0)
{
hash[v]=1;
Queue.push(v);
Times[v]++;
}
}
}
hash[u]=0;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
double L=1e-10,R=101;
for(int i=1;i<=m;i++)
{
int p,q;
double u,v;
scanf("%d%d%lf%lf",&p,&q,&u,&v);
Add(p,q,u,v,i);
}
for(;L+1e-10<=R;)
{
double mid=(L+R)/2;
if(check(mid))
L=mid;
else R=mid;
}
vector <int> V;
int st=check(L);
if(st==0)
{
printf("0\n");
return 0;
}
memset(hash,0,sizeof(hash));
for(;hash[st]<=1;st=father[st])
{
hash[st]++;
if(hash[st]==2)
V.push_back(st);
}
printf("%d\n",V.size());
for(int i=V.size()-1;i>=0;i--)
printf("%d ",V[i]);
puts("");
return 0;
}
原文:http://blog.csdn.net/qq_21995319/article/details/44206509