博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网络流
阅读量:5049 次
发布时间:2019-06-12

本文共 5974 字,大约阅读时间需要 19 分钟。

HDU4862 这题说的是在一个n*m的格子内 你有K次机会选择起始的点,选择的点不能使以前用过的 ,然后选择后你可以往右 跳几步 也可以往下跳几步 但是只能要不往右 要不就往下 不能两个同时成立比如说 (1,1) 不能跳到(2,3);然后得到了 我们通过 拆点可以将他们分离开来保证只用一次,然后将拆的点的流量置为1 费用置为 负的无穷大,这样是为了勾引流量过来使得k次选择的点能够通过所有的点然后还要外加一条边是从源点流向汇点的这条边的流量为k 费用为0  这条边的目的是为了使得如果选择次数比k次来的小的时候可能达到最大值就不去影响那个最大值因为他保证可以使用少于k次的选择机会

#include 
#include
#include
#include
using namespace std;const int MOD = 100000;const int INF = 100000000;const int maxn = 1000000;int first[300],next[maxn],u[maxn],v[maxn],w[maxn],num,cost[maxn],ed,st,map[200][200];int per[300],mark[300],dis[300],n,m;void add(int a, int b, int c, int d){ u[num] = a; v[num] = b; w[num] = c; cost[num] = d; next[num] = first[a]; first[a] = num++; u[num] = b; v[num] = a; w[num] = 0; cost[num] = -d; next[num] = first[b]; first[b]=num++;}int abs(int a){ return a>0?a:-a; }bool SPAF(){ for(int i =0; i<= ed+1; ++i) dis[i]=INF,mark[i]=0,per[i]=-1; dis[ed+1]=0; queue
Q; Q.push(ed+1); while(!Q.empty()) { int a = Q.front(); Q.pop(); mark[a]=0; for(int e =first[a]; e!=-1; e= next[e]) if(dis[v[e]]>dis[u[e]]+cost[e]&&w[e]>0) { dis[ v[ e ] ] = dis[ u[ e ] ] +cost[ e ]; per[v[e]] = e; if(mark[v[e]]==0) { mark[v[e]] = 1; Q.push(v[e]); } } } return dis[ed]!=INF;}int EK(){ int ans_COS=0 ; while(SPAF()) { int flow =INF; for( int e=per[ed]; e!=-1; e=per[ u[e] ] ) if(flow>w[e]) flow=w[e]; for(int e = per[ed]; e!=-1; e=per[u[e]]) { w[e]-=flow; w[e^1]+=flow; } ans_COS+=dis[ed]; } return (-(n*m*MOD+ans_COS))%MOD;}int main(){ int t; scanf("%d",&t); for( int cas = 1 ; cas<=t; ++cas ) { int n,m,K; scanf("%d%d%d",&n,&m,&K); ed =n*m*2+1; for(int i =0; i<=ed+1; ++i) first[i]=-1; st=num=0; for(int i =1; i<=n; ++ i) for(int j =1; j<=m; ++j) { scanf("%1d",&map[i][j]); add( st, (i-1)*m+j , 1, 0); add( ( i - 1 )*m+j, n*m+( i - 1 )*m+j, 1, -MOD ); add( n * m +( i - 1 )*m+j, ed, 1, 0 ); } if(K
View Code

题解是用 二部图做的最小K路径覆盖的模型,用费用流或者KM算法解决,构造二部图,X部有N*M个节点,源点向X部每个节点连一条边,流量1,费用0Y部有N*M个节点,每个节点向汇点连一条边,流量1,费用0,如果X部的节点x可以在一步之内到达Y部的节点y,那么就连边x->y,费用为从x格子到y格子的花费能量减去得到的能量,流量1,再在X部增加一个新的节点,表示可以从任意节点出发K次,源点向其连边,费用0,流量K,这个点向Y部每个点连边,费用0,流量1,最这个图跑最小费用最大流,如果满流就是存在解,反之不存在,最小费用的相反数就是可以获得的最大能量

#include 
#include
#include
#include
using namespace std;const int INF = 100000;const int maxn=100000;int first[300],next[maxn],u[maxn],v[maxn],cost[maxn],w[maxn],ed,num,st,n,m,k;int dis[300],mark[300],per[300],map[300][300];int abs(int a){ return a>0?a:-a; }void add(int a,int b, int flow, int cos){ u[ num ] = a; v[ num ] = b; w[ num ] = flow; cost[ num ] = cos; next[ num ] = first[a]; first[ a ] = num++; u[ num ]=b; v[ num ]=a; w[ num ] = 0; cost[ num ] = -cos; next[ num ] = first[b]; first[ b ]=num++;}bool SPAF(){ for(int i =0; i<=ed+1; ++i) mark[i]=0,per[i]=-1,dis[i]=INF; queue
Q; Q.push(st); dis[st]=0; while(!Q.empty()) { int a = Q.front(); Q.pop(); mark[a] =0; for(int e = first[a] ; e!=-1; e=next[e]) if( dis[v[e]]>dis[u[e]]+cost[e] && w[e]>0) { dis[ v[ e ] ] = dis[ u[ e ] ] +cost[ e ]; per[ v[ e ] ] = e; if(mark[v[e]] == 0) { mark[ v[ e ] ] = 1; Q.push(v[ e ]); } } } return dis[ed]!=INF;}int EK(){ int Cos_t=0,Cos_flow=0; while(SPAF()) { int flow=INF; for(int e = per[ed] ; e!=-1; e =per[u[e]]) if(flow>w[e]) flow=w[e]; for(int e = per[ed] ; e!=-1; e = per[u[e]] ) { w[e]-=flow; w[e^1]+=flow; } Cos_t+=dis[ed]; Cos_flow+=flow; } if(Cos_flow==n*m) return - Cos_t; else return -1;}int main(){ int t; scanf("%d",&t); for( int cas = 1; cas <= t ; cas++ ) { scanf("%d%d%d",&n,&m,&k); st=num=0; ed= n*m*2 +1; for(int i=0; i<=ed+1; ++i) first[i]=-1; for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) { scanf("%1d",&map[i][j]); add( st, (i-1)*m+j, 1, 0); add( n*m+(i-1)*m+j, ed, 1, 0); } for(int i =1; i<=n; ++i) for(int j =1; j<=m; ++j) { for(int k =i+1; k<=n; ++k) add( (i-1)*m+j, n*m+(k-1)*m+j, 1,abs(k-i)-1-(map[i][j]==map[k][j]?map[i][j]:0)); for(int k=j+1; k<=m; ++k) add( (i-1)*m+j, n*m+(i-1)*m+k, 1,abs(k-j)-1-(map[i][j]==map[i][k]?map[i][j]:0)); add( ed+1, n*m+(i-1)*m+j, 1, 0); } add(st,ed+1,k,0); int ans=EK(); printf("Case %d : %d\n",cas,ans); } return 0;}
View Code

的堆得得得得

转载于:https://www.cnblogs.com/Opaser/p/3861735.html

你可能感兴趣的文章
CURL 支持 GET、PUT、POST、DELETE请求
查看>>
.net(c#)中的new关键字
查看>>
【文智背后的奥秘】系列篇——文本聚类系统
查看>>
实时信号
查看>>
struct和typedef struct的区别
查看>>
内存测试——Android Studio中对应进程的Heap
查看>>
『校内OJ』NOIP2019模拟赛(二)
查看>>
mongodb-安装&配置&启动
查看>>
Oracle按数字大小排序
查看>>
在Visual Studio中使用MonoTouch开发iOS应用程序
查看>>
python入门作业---ATM+购物商场程序(2)
查看>>
仿射函数
查看>>
(一) Keras 一元线性回归
查看>>
Unity的50个使用技巧(2016 Edition)
查看>>
HDU 2050(折线分割平面)
查看>>
sql 存储过程—分页获取信息
查看>>
okhttp3 get post 简单封装
查看>>
基础网络相关概念
查看>>
2010年初关注的技术
查看>>
Git——新手入门与上传项目到远程仓库GitHub
查看>>