「USACO2007DEC」Sightseeing Cows 题解报告
作者:互联网
题目大意
给定一张图,边上有花费,点上有收益,点可以多次经过,但是收益不叠加,边也可以多次经过,但是费用叠加。求一个环使得收益和/花费和最大,输出这个比值。
样例
样例输入1
5 7
30
10
10
5
10
1 2 3
2 3 2
3 4 5
3 5 2
4 5 5
5 1 3
5 2 2
样例输出1
6.00
思路
就是板子啦!
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+2;//max-n
int n,m,cnt,x,y,z;
int fir[N],sum[N],vis[N],to[N<<1],nxt[N<<1];
double mid,dis[N],a[N],w[N<<1];
void add(int x,int y,int z){
nxt[++cnt]=fir[x];
fir[x]=cnt;
to[cnt]=y;
w[cnt]=z;
}//前向星建图_(:з」∠)_
bool spfa(int s){//判负环
memset(vis,0,sizeof(vis));//初始化
memset(sum,0,sizeof(sum));//初始化 1到x的最短路径包含的边数
//用来判负环,cnt[x]>=n就表示有负环(原因显然好伐)
memset(dis,0x3f,sizeof(dis));//极大值
queue<int>q;
q.push(s);
vis[s]=1;//维护标记数组
dis[s]=0;//自己到自己距离显然为0(#`O′)
while(!q.empty()){
int p=q.front();q.pop();
for(int u=fir[p];u;u=nxt[u]){//遍历
int v=to[u];//方便书写︿( ̄︶ ̄)︿
vis[v]=0;//维护标记数组
if(dis[v]>dis[p]+w[u]*mid-a[p]){//最短路
dis[v]=dis[p]+w[u]*mid-a[p];//更新
if(!vis[v]){//没有经过过
sum[v]++;//边数++
vis[v]=1;//标记已经经过
q.push(v);//点放入堆中
if(sum[v]>=n) return 1;//有负环 ε=(′ο`*)))
}
}
}
}
return 0;//没得负环\(^o^)/~
}
bool check(double mid){
for(int i=1;i<=n;i++) {
if(spfa(i)) return 1;//有负环
}
return 0;//无负环
}
double solve(){
double l=0.0,r=100.0;
while(r-l>=1e-3){//避免精度误差,相当于l<=r
mid=(l+r)/2;
if(check(mid)) l=mid;//case 1 :<0(有负环)
else r=mid;//case 2:>=0(有负环)
}
return l;//返回答案O(∩_∩)O
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%lf",&a[i]);//输入
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);//建边
}
printf("%.2lf",solve());//答案出来啦(^-^)V
return 0;
}
完结撒花❀
✿✿ヽ(°▽°)ノ✿
标签:return,int,题解,USACO2007DEC,样例,负环,vis,Cows,dis 来源: https://www.cnblogs.com/Aurora1217/p/16365530.html