费用流
建图还是比较简单的。。。(参见下面代码)
#include<cstdio> #include<cstring> #include<queue> #define N 100 #define inf 100000000 using namespace std; int cre[N],tot_cre; int sco[N]; int head[N],cnt,dis[N],pre[N],vis[N],ans[N]; int n; struct Edge{ int u,v,c,w,next; }edge[80010]; void addedge(int u,int v,int cap,int cost){ edge[cnt].u=u; edge[cnt].v=v; edge[cnt].c=cap; edge[cnt].w=cost; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].u=v; edge[cnt].v=u; edge[cnt].c=0; edge[cnt].w=-cost; edge[cnt].next=head[v]; head[v]=cnt++; } bool spfa(){ int i,j; queue<int>q; q.push(0); for(i=1;i<=n;i++) dis[i]=-inf,vis[i]=0; dis[i]=0,vis[0]=1; while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=0; for(i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(edge[i].c && dis[v] < dis[u]+edge[i].w){ dis[v]=dis[u]+edge[i].w; pre[v]=i; if(!vis[v]){ vis[v]=1; q.push(v); } } } } if(dis[n]==-inf)return 0; return 1; } void end(){ int u,p,cap=-1; for(u=n;u;u=edge[p].u){ p=pre[u]; if(cap==-1 || cap>edge[p].c) cap=edge[p].c; } for(u=n;u;u=edge[p].u){ p=pre[u]; edge[p].c-=cap; edge[p^1].c+=cap; } } void init(){ memset(head,-1,sizeof(head)); memset(ans,0,sizeof(ans)); cnt=tot_cre=0; } int main(){ int i,j; int v,e,k; int pre,now,tem; while(scanf("%d %d %d",&v,&k,&e)){ if(v==0 && k==0 && e==0)break; init(); for(i=1;i<=e;i++){ scanf("%d",&cre[i]); tot_cre+=cre[i]; } n=v+e+1; for(i=1;i<=v;i++) addedge(0,i,k,0); for(i=1;i<=e;i++){ scanf("%d",&sco[i]); if(sco[i]<60){ pre=6400-3*(100-60)*(100-60); addedge(i+v,n,60-sco[i],inf); for(j=61;j<=100;j++){ now=6400-3*(100-j)*(100-j); addedge(i+v,n,1,(now-pre)*cre[i]); pre=now; } } else{ pre=6400-3*(100-sco[i])*(100-sco[i]); for(j=sco[i]+1;j<=100;j++){ now=6400-3*(100-j)*(100-j); addedge(i+v,n,1,(now-pre)*cre[i]); pre=now; } } } for(i=1;i<=v;i++) for(j=1;j<=e;j++){ scanf("%d",&tem); if(tem) addedge(i,v+j,k,0); } while(spfa()) end(); for(i=head[n];i!=-1;i=edge[i].next) ans[edge[i].v-v]+=edge[i].c; bool flag=1; int sum=0; for(i=1;i<=e;i++){ if(ans[i]+sco[i]<60){ flag=0; break; } sum+=(6400-3*(100-ans[i]-sco[i])*(100-ans[i]-sco[i]))*cre[i]; } if(!flag)printf("0.000000\n"); else printf("%.6lf\n",(double)sum/tot_cre/1600); } }
如果边权用的是double类型的话一定记得加上eps
见下面代码(注意加上//////的代码)
#include<cstdio> #include<cstring> #include<queue> #include<cmath> #define N 100 #define inf 100000000 using namespace std; int cre[N],tot_cre; int sco[N]; int head[N],cnt,pre[N],vis[N],ans[N]; double dis[N]; int n; struct Edge{ int u,v,c,next; double w; }edge[80010]; void addedge(int u,int v,int cap,double cost){ edge[cnt].u=u; edge[cnt].v=v; edge[cnt].c=cap; edge[cnt].w=cost; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].u=v; edge[cnt].v=u; edge[cnt].c=0; edge[cnt].w=-cost; edge[cnt].next=head[v]; head[v]=cnt++; } bool spfa(){ int i,j; queue<int>q; q.push(0); for(i=1;i<=n;i++) dis[i]=-inf,vis[i]=0; dis[i]=0,vis[0]=1; while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=0; for(i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(edge[i].c && dis[v]-dis[u]-edge[i].w<-1e-9){ ///// dis[v]=dis[u]+edge[i].w; pre[v]=i; if(!vis[v]){ vis[v]=1; q.push(v); } } } } if(fabs(dis[n]+inf)<1e-9)return 0; ///// return 1; } void end(){ int u,p,cap=-1; for(u=n;u;u=edge[p].u){ p=pre[u]; if(cap==-1 || cap>edge[p].c) cap=edge[p].c; } for(u=n;u;u=edge[p].u){ p=pre[u]; edge[p].c-=cap; edge[p^1].c+=cap; } } void init(){ memset(head,-1,sizeof(head)); memset(ans,0,sizeof(ans)); cnt=tot_cre=0; } int main(){ int i,j; int v,e,k; int pre,now,tem; while(scanf("%d %d %d",&v,&k,&e)){ if(v==0 && k==0 && e==0)break; init(); for(i=1;i<=e;i++){ scanf("%d",&cre[i]); tot_cre+=cre[i]; } n=v+e+1; for(i=1;i<=v;i++) addedge(0,i,k,0); for(i=1;i<=e;i++){ scanf("%d",&sco[i]); if(sco[i]<60){ pre=6400-3*(100-60)*(100-60); addedge(i+v,n,60-sco[i],inf); for(j=61;j<=100;j++){ now=6400-3*(100-j)*(100-j); addedge(i+v,n,1,((double)now-pre)*cre[i]/(tot_cre*1600)); pre=now; } } else{ pre=6400-3*(100-sco[i])*(100-sco[i]); for(j=sco[i]+1;j<=100;j++){ now=6400-3*(100-j)*(100-j); addedge(i+v,n,1,((double)now-pre)*cre[i]/(tot_cre*1600)); pre=now; } } } for(i=1;i<=v;i++) for(j=1;j<=e;j++){ scanf("%d",&tem); if(tem) addedge(i,v+j,k,0); } while(spfa()) end(); for(i=head[n];i!=-1;i=edge[i].next) ans[edge[i].v-v]+=edge[i].c; bool flag=1; double sum=0; for(i=1;i<=e;i++){ if(ans[i]+sco[i]<60){ flag=0; break; } sum+=((double)6400-(double)3*(100-ans[i]-sco[i])*(100-ans[i]-sco[i]))*cre[i]/(tot_cre*1600); } if(!flag)printf("0.000000\n"); else printf("%.6lf\n",sum); } }