zoukankan      html  css  js  c++  java
  • HDU 4862(费用流)

    Problem Jump (HDU4862)

    题目大意

      给定一个n*m的矩形(n,m≤10),每个矩形中有一个0~9的数字。

      一共可以进行k次游戏,每次游戏可以任意选取一个没有经过的格子为起点,并且跳任意多步,每步可以向右方和下方跳。每次跳需要消耗两点间的曼哈顿距离减一的能量,若每次跳的起点和终点的数字相同,可以获得该数字的能量。(能量可以为负)

      询问k次或更少次游戏后是否可以经过所有的格子,若可以求出最大的剩余能量。

    解题分析

      带权值的最小K路径覆盖。

      (最小路径覆盖数=总节点数-最大匹配数)

      将n*m个点,每个点拆成两个,X,Y。

      由S向X连容量为1费用为0的边,Y向T连容量为1费用为0的边,X向可到达的Y连容量为1费用为所消耗能量(加上所得)。

      这样直接跑可求出最大匹配数。所有未流满的Y点数量即为最小路径覆盖数。

      考虑如何实现K路径覆盖。

      新建一个点Q,由S向Q连容量为k费用为0的边,有Q向Y连容量为1费用为0的边。即表示可以新增的起点数为k。

      这样跑一遍最小费用最大流,若不是满流则说明无解。

    参考程序

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <queue>
      5 using namespace std;
      6 
      7 #define V 2008
      8 #define E 1000008
      9 #define INF 200000000
     10 int n,m,k,S,T,Que,num;
     11 int a[V][V],mark[V][V];
     12 
     13 int pd[V],dis[V],pre[V];
     14 struct line{
     15     int u,v,c,w,nt;
     16 }eg[E];
     17 int lt[V],sum;
     18 
     19 void adt(int u,int v,int c,int w) {
     20     eg[++sum].u=u; eg[sum].v=v; eg[sum].c=c; 
     21     eg[sum].w=w; eg[sum].nt=lt[u]; lt[u]=sum;
     22 }
     23 
     24 void add(int u,int v,int c,int w) {
     25     adt(u,v,c,w); adt(v,u,0,-w);
     26     //printf("%d %d %d %d
    ",u,v,c,w);
     27 }
     28 
     29 void init(){
     30 
     31     sum=1; num=0;
     32     memset(lt,0,sizeof(lt));
     33 
     34     char  s[V];
     35     scanf("%d %d %d",&n,&m,&k);
     36     for (int i=1;i<=n;i++){
     37         scanf("%s",s+1);
     38         for (int j=1;j<=m;j++)
     39         {
     40             a[i][j]=s[j]-'0';
     41             mark[i][j]=++num;
     42         }
     43     }
     44 
     45     S=0; T=num*2+2;
     46     add(S,T-1,k,0);
     47     for (int i=1;i<=n;i++)
     48         for (int j=1;j<=m;j++)
     49         {
     50             add(S,mark[i][j],1,0);
     51             add(mark[i][j]+num,T,1,0);    
     52             add(T-1,mark[i][j]+num,1,0);
     53         }
     54     for (int i=1;i<=n;i++)
     55         for (int j=1;j<=m;j++)
     56             for (int k=1;k<=n;k++)
     57                 for (int l=1;l<=m;l++)
     58                     if (i==k && l>j || j==l && k>i)
     59                     {   
     60                         int x=abs(i-k)+abs(j-l)-1;
     61                         if (a[i][j]==a[k][l]) x-=a[i][j];
     62                         add(mark[i][j],mark[k][l]+num,1,x);
     63                     }
     64     n=T;
     65 }
     66 
     67 bool spfa() {
     68     queue <int> Q;
     69     for (int i=0;i<=n;i++) {
     70         dis[i]=INF;
     71         pd[i]=0;
     72         pre[i]=-1;
     73     }
     74     dis[S]=0; pd[S]=1; Q.push(S);
     75     while (!Q.empty()) {
     76         int u = Q.front();
     77         for (int i=lt[u];i;i=eg[i].nt) 
     78             if (eg[i].c>0) {
     79                 int v=eg[i].v;
     80                 if (dis[u]+eg[i].w<dis[v]) {
     81                     dis[v]=dis[u]+eg[i].w;
     82                     pre[v]=i;
     83                     if (!pd[v]) {
     84                         Q.push(v);
     85                         pd[v]=1;
     86                     }
     87                 }
     88             }
     89         pd[u]=0;
     90         Q.pop();
     91     }
     92     return dis[T]!=INF;
     93 }
     94 
     95 void minCmaxF(){
     96     int minC=0,maxF=0,flow;
     97     while (spfa()) {
     98         flow=INF;
     99         for (int i=pre[T];~i;i=pre[eg[i].u])
    100             flow=min(flow,eg[i].c);
    101         for (int i=pre[T];~i;i=pre[eg[i].u]) {
    102             eg[i].c-=flow;
    103             eg[i^1].c+=flow;
    104         }
    105         maxF+=flow;
    106         minC+=flow*dis[T];
    107     }
    108    if (maxF==num) printf("%d
    ",-minC); else printf("-1
    ");
    109    
    110 }
    111 
    112 int main(){
    113     scanf("%d",&Que);
    114     for (int tt=1;tt<=Que;tt++){
    115         init();
    116         printf("Case %d : ",tt  );
    117         minCmaxF();
    118     }
    119 }
    View Code
  • 相关阅读:
    Vue之常用语法
    Django之crm
    Django项目之客户
    前端、数据库、Django简单的练习
    Django的认证系统
    Django之form表单
    OpneCV 二值图像区域处理
    OpenCV图像处理中常用函数汇总(1)
    OpenCV3编程入门笔记(6)自我验证各函数程序代码
    OpenCV_轮廓的查找、表达、绘制、特性及匹配
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/5716305.html
Copyright © 2011-2022 走看看