设为首页 加入收藏

TOP

hdu4862 2014多校B题/ 费用流(最优情况下用不大于K条路径覆盖)(不同的解法)
2015-07-20 18:03:33 来源: 作者: 【 】 浏览:2
Tags:hdu4862 2014 多校 费用 情况 大于 路径 覆盖 不同 解法

题意: 一个数字矩阵,可以出发K次,每次可以从右边或者下面走,要求(在收益最大情况下)覆盖全图,不能则输出-1。(规则:每次跳一步的时候若格子数字相等则获得该数字的能量,每跳一步消耗距离的能量)。每个格子走且仅能走一次。

选<=K条路径,最优情况来覆盖全图。

显然用拆点为二分图。

一种解法:边(流量,费用)

源点向X部连边(1,0)Y部向汇点连边(1,0)X到Y,若能到,则有边(1,消耗-获得)。关键点(解决每个点都覆盖,恰好起到填补的作用):在X部最上面添加一个点,源点连之(k,0)它向所有Y点连边(1,0)。跑最小费用最大流即可。

第二种:(感想zz1215提供的建图思路)

源点向X部连边(1,0)Y部向汇点连边(1,0),Y到X,若能到,则有边(1,消耗-获得)(注意这里是回流),每个点I-->I`有边(1,-w_inf),这里的w_inf为相对大数,只要保证该费用较“小”即可(相对其他费用,他是最廉价的,这样必优先流这条边。添加超级源点,向源点连边(K,0)。增广K次中,若一直增大,则取最大,否则到开始下降的时候要BREAK。(先曾后减的)。

PS:开始时候因为定位编号搞错有没有!编号(i,j)=i*m+j,而不是i*n+j!!!

图:\


<??http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+tPrC66O6PC9wPgo8cD48cHJlIGNsYXNzPQ=="brush:java;">#include //24ms #include #include #include #include using namespace std; int n,m,k; const int inf=0x3f3f3f3f; int a[25][25]; int head[500];int e[10000][4];int nume=0; void inline adde(int i,int j,int c,int w) { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume][2]=c;e[nume++][3]=w; e[nume][0]=i;e[nume][1]=head[j];head[j]=nume; e[nume][2]=0;e[nume++][3]=-w; } int inq[500];int d[500]; bool spfa(int &sumcost) { for(int i=0;i<=2*n*m+3;i++) { inq[i]=0;d[i]=inf; } int minf=inf; queue q; int prv[300];int pre[300]; q.push(2*n*m+2); inq[2*n*m+2]=1; d[2*n*m+2]=0; while(!q.empty()) { int cur=q.front(); q.pop();inq[cur]=0; for(int i=head[cur];i!=-1;i=e[i][1]) { int v=e[i][0]; if(e[i][2]>0&&d[v]>e[i][3]+d[cur]) { d[v]=e[i][3]+d[cur]; prv[v]=cur; pre[v]=i; if(!inq[v]) { q.push(v); inq[v]=1; } } } } if(d[2*n*m+1]==inf)return 0; int cur=2*n*m+1; while(cur!=2*n*m+2) { minf=min(minf,e[pre[cur]][2]); cur=prv[cur]; } cur=2*n*m+1; while(cur!=2*n*m+2) { e[pre[cur]][2]-=minf;e[pre[cur]^1][2]+=minf; cur=prv[cur]; } sumcost+=d[2*n*m+1]*minf; return 1; } int mincost() { int sum=0; while(spfa(sum)); return sum; } void init() { nume=0; for(int i=0;i<=2*n*m+3;i++) { head[i]=-1; } } int main() { int T; scanf("%d",&T); for(int iii=1;iii<=T;iii++) { scanf("%d%d%d",&n,&m,&k); init(); string s; for(int i=0;i >s; for(int j=0;j k) { printf("-1\n");continue; } for(int i=0;i %d:c:%d,w:%d\n",i,e[j][0],e[j][2],e[j][3]);*/ printf("%d\n",-mincost()); } return 0; }


方法二:

#include
  
              //31ms
#include
   
     #include
    
      #include
     
       using namespace std; int n,m,k; const int inf=0x3f3f3f3f; const int winf=100000; int a[25][25]; int head[500];int e[20001][4];int nume=0; void inline adde(int i,int j,int c,int w) { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume][2]=c;e[nume++][3]=w; e[nume][0]=i;e[nume][1]=head[j];head[j]=nume; e[nume][2]=0;e[nume++][3]=-w; } int inq[500];int d[500]; bool spfa(long long &sumcost) { for(int i=0;i<=2*n*m+3;i++) { inq[i]=0;d[i]=inf; } int prv[500];int pre[500]; int minf=inf; queue
      
       q; q.push(n*m); inq[n*m]=1; d[n*m]=0; while(!q.empty()) { int cur=q.front(); q.pop(); inq[cur]=0; for(int i=head[cur];i!=-1;i=e[i][1]) { int v=e[i][0]; if(e[i][2]>0&&d[v]>e[i][3]+d[cur]) { d[v]=e[i][3]+d[cur]; prv[v]=cur; pre[v]=i; if(!inq[v]) { q.push(v); inq[v]=1; } } } } if(d[2*n*m+1]==inf)return 0; int cur=2*n*m+1; while(cur!=n*m) { minf=min(minf,e[pre[cur]][2]); cur=prv[cur]; } cur=2*n*m+1; while(cur!=n*m) { e[pre[cur]][2]-=minf; e[pre[cur]^1][2]+=minf; cur=prv[cur]; } sumcost+=d[2*n*m+1]*(long long)minf; return 1; } long long mincost() { long long sum=0; long long lastsum=0; while(spfa(sum)) //变小的时候跳出 { if(lastsum>=-sum){return -lastsum;} lastsum=-sum; } return sum; } void init() { nume=0; for(int i=0;i<=2*n*m+3;i++) { head[i]=-1; } } int main() { int T; scanf("%d",&T); for(int iii=1;iii<=T;iii++) { scanf("%d%d%d",&n,&m,&k); init(); string s; for(int i=0;i
       
        >s; for(int j=0;j
        
         k) { printf("-1\n");continue; } for(int i=0;i
         
          %d:c:%d,w:%d\n",i,e[j][0],e[j][2],e[j][3]);*/ cout<<-mincost()-n*m*winf<
          
           


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇vim-snippets Ultisnips的写法 下一篇HDU 2072 单词数

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: