2017.9.14 星际竞速 失败总结

来源:互联网 发布:网络事件 2017 编辑:程序博客网 时间:2024/05/22 15:20

这个题就是要选一些边,覆盖所有点,并且边的权值和最小

然后这是一开始建的图:


有如下问题:

1、边数太多

2、最大流不满足问题性质

为了解决2,我们必须让每一个方案都满足最大流的条件

原图的问题是:想用一条流量干和许多流量等价的事(一条流量流1、 2  一条流量流3),那必然会导致最大流和方案是不协调的

所以我们必须让一条流量 干有且仅有一个事

这样最大流就和方案等价了

题目有一个很强的条件,即每个点的都只有一次,

所以我们需要为每一种决策给予一个流量,让费用流选出最优的一条流向t

还有一个很强的用于优化的性质:无论什么点,跳到一个点的费用是相同的

所以就直接从s连向每个点表示就好了

根据dag可知匹配不会有环

这个题的主要思想是既然每个点都会被走到,那就每个点都进行走其他点的决策,而每个点只接受一个决策

这样做相当于离散了一下,跑出来不是具体的方案,是一些关系,这些关系都满足整体条件,利用有且仅有一次的特点推广到每个点的决策,再推广到每个点的选取,

相当于拆点,一个表示到过,一个表示决策,到过不能向决策连边,因为到过要满足最大流的性质


注意:空间,行的字数超过界面了注意滚动条往右查看变量有没有问题


码:

#include<iostream>#include<cstdio>#include<cstring>#include<queue>using namespace std; queue<int>q;bool vis[2000];int s,t,xia[2000],hou[2000000],qj[2000],tot=-1,ans,v[2000000],cc[2000000],dis[2000],a[2000],j,m,i,n,x,y,z,zhong[2000000];void jian(int a,int b,int c,int d){++tot;hou[tot]=xia[a];xia[a]=tot;zhong[tot]=b;v[tot]=c;cc[tot]=d;}void jia(int a,int b,int c){jian(a,b,1,c);jian(b,a,0,-c);}bool spfa(){int i;memset(vis,0,sizeof(vis));memset(dis,0x7f,sizeof(dis));q.push(s);qj[s]=0;dis[s]=0;while(!q.empty()){int st=q.front();q.pop();    vis[st]=0;for(i=xia[st];i!=-1;i=hou[i]){int nd=zhong[i];if(v[i]>0&&dis[nd]>dis[st]+cc[i]){dis[nd]=dis[st]+cc[i];//cout<<st<<" "<<nd<<" "<<dis[nd]<<endl;qj[nd]=i^1;if(vis[nd]==0){q.push(nd);vis[nd]=1;}}}}if(dis[t]>1000000000)return 0;for(i=qj[t];i;i=qj[zhong[i]]){v[i]+=1;v[i^1]-=1;ans+=cc[i^1];}return 1;}int main(){memset(xia,-1,sizeof(xia));scanf("%d%d",&n,&m);for(i=1;i<=n;i++){scanf("%d",&a[i]);//cout<<i<<" "<<a[i]<<endl;}for(i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&z);if(x>y)swap(x,y);jia(x+n,y,z);}s=n*2+2;t=n*2+3;for(i=1;i<=n;i++){jia(s,i,a[i]);jia(s,i+n,0);jia(i,t,0); }   while(spfa());printf("%d",ans);}








原创粉丝点击