hdu3338 / 方格横纵和问题终极版,最大流斩

此题被誉为神奇最大流,诱惑我去做了下,感觉也是通常的思路。

题意:1.用1-9去填,满足所给的行/列和要求(和那个什么游戏差不多。。。)

求一种合法方案,输出。如:

              

一看,直接就建图了,每个点在白色的点中间,由横和=纵和,管理横和的在左边,纵和的点在右边。S->横和点,纵和点到t,建图即可。

有一点注意,由于只能用1-9去填,是有上下界的网络流问题,所以这里有点比较巧妙,所有白色的点都减去1,和也对应减去几。用0做1,1做2...8做9.一一对应,实现转移为一般最大流问题。最后再加一即可。

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxv=20100,maxe=1000101;
int nume=0;int head[maxv];int e[maxe][3];
void inline adde(int i,int j,int c)
{
    e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
    e[nume++][2]=c;
    e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
    e[nume++][2]=0;
}
int ss,tt,n,m;
int vis[maxv];int lev[maxv];
bool bfs()
{
    for(int i=0;i<maxv;i++)
      vis[i]=lev[i]=0;
    queue<int>q;
    q.push(ss);
    vis[ss]=1;
    while(!q.empty())
    {
        int cur=q.front();
        q.pop();
        for(int i=head[cur];i!=-1;i=e[i][1])
        {
            int v=e[i][0];
            if(!vis[v]&&e[i][2]>0)
            {
                lev[v]=lev[cur]+1;
                vis[v]=1;
                q.push(v);
            }
        }
    }
    return vis[tt];
}
int dfs(int u,int minf)
{
    if(u==tt||minf==0)return minf;
    int sumf=0,f;
    for(int i=head[u];i!=-1&&minf;i=e[i][1])
    {
        int v=e[i][0];
        if(lev[v]==lev[u]+1&&e[i][2]>0)
        {
            f=dfs(v,minf<e[i][2]?minf:e[i][2]);
            e[i][2]-=f;e[i^1][2]+=f;
            sumf+=f;minf-=f;
        }
    }
    if(!sumf) lev[u]=-1;
    return sumf;
}
int dinic()
{
    int sum=0;
    while(bfs())sum+=dfs(ss,inf);
    return sum;
}
struct cell         //方块
{
     int clour;
     int x,y;
};
cell ces[102][102];
void read_build()
{
    string ts;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
            cin>>ts;
            if(ts=="XXXXXXX")      //黑色
              {
                  ces[i][j].clour=0;
                  ces[i][j].x=ces[i][j].y=-1;
              }
            else if(ts==".......")   //白色
            {
                 ces[i][j].clour=5;
                 ces[i][j].x=ces[i][j].y=0;
            }
            else if(ts[0]=='X'&&ts[4]!='X')    //横向要填
            {
                 ces[i][j].clour=2;
                 ces[i][j].x=((ts[4]-'0')*10+(ts[5]-'0'))*10+(ts[6]-'0');
                 ces[i][j].y=-1;
            }
             else if(ts[0]!='X'&&ts[4]=='X')   //纵向要填
            {
                 ces[i][j].clour=3;
                 ces[i][j].y=((ts[0]-'0')*10+(ts[1]-'0'))*10+(ts[2]-'0');
                 ces[i][j].x=-1;
            }
            else                          //都要
            {
                 ces[i][j].clour=4;
                 ces[i][j].y=((ts[0]-'0')*10+(ts[1]-'0'))*10+(ts[2]-'0');
                 ces[i][j].x=((ts[4]-'0')*10+(ts[5]-'0'))*10+(ts[6]-'0');
            }
        }
      for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
       {
           //cout<<ces[i][j].clour<<endl;
         //  cout<<i*m+j<<" ";
       }

    for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
      {
          int counts=0;
          if(ces[i][j].clour==2) //横向的
          {
              for(int k=j+1;k<m;k++)
              {
                  if(ces[i][k].clour!=5)break;
                  adde(i*m+j,i*m+k,8);
                  counts++;
              }
              adde(ss,i*m+j,ces[i][j].x-counts);
          }
          else if(ces[i][j].clour==3)   //纵向的
         {
              for(int k=i+1;k<n;k++)
              {
                 if(ces[k][j].clour!=5)break;
                  adde(k*m+j,i*m+j,8);
                  counts++;
              }
              adde(i*m+j,tt,ces[i][j].y-counts);
          }
           else if(ces[i][j].clour==4)    //都要填的,一个格子要2个编号,注意。
         {

              for(int k=j+1;k<m;k++)
              {
                 if(ces[i][k].clour!=5)break;
                  adde(i*m+j,i*m+k,8);
                  counts++;
              }
              adde(ss,i*m+j,ces[i][j].x-counts);
            counts=0;
              for(int k=i+1;k<n;k++)
              {
                   if(ces[k][j].clour!=5)break;
                  adde(k*m+j,i*m+j+n*m+2,8);
                  counts++;
              }
              adde(i*m+j+n*m+2,tt,ces[i][j].y-counts);
          }
      }
     // adde(0,ss,2);
   /* for(int i=0;i<=n*m+1;i++)
      for(int j=head[i];j!=-1;j=e[j][1])
      {
          printf("%d->%d:%d\n",i,e[j][0],e[j][2]);
      }*/
}
void out()
{
    for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
      {
          if(ces[i][j].clour!=5)printf("_");
          else
          {
              int sflow=0;
              for(int k=head[i*m+j];k!=-1;k=e[k][1])      //统计的时候只要正向边(这里注意!),其实每个点也就一条出的正向边
              {
                  if(k%2==0)
                   sflow+=8-e[k][2];
              }
              printf("%d",sflow+1);
          }
          if(j==m-1)printf("\n");
          else printf(" ");
      }
}
void init()
{
    nume=0;
    memset(head,-1,sizeof(head));
    ss=n*m;tt=n*m+1;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        read_build();
        dinic();
        out();
    }
    return 0;
}

hdu3338 / 方格横纵和问题终极版,最大流斩

时间: 2024-09-30 10:41:40

hdu3338 / 方格横纵和问题终极版,最大流斩的相关文章

自制进制转换终极版

/** * 自制进制转换终极版 * 过程不重复了. */ public class TransFinal { public static void main(String[] args) { int num = 26; String hex = toHex(num); String oct = toOct(num); String bin = toBin(num); System.out.println("十六进制: "+ hex); System.out.println("

[转]py编码终极版

py编码终极版 原文链接:http://www.cnblogs.com/yuanchenqi/articles/5956943.html 一 什么是编码? 基本概念很简单.首先,我们从一段信息即消息说起,消息以人类可以理解.易懂的表示存在.我打算将这种表示称为"明文"(plain text).对于说英语的人,纸张上打印的或屏幕上显示的英文单词都算作明文. 其次,我们需要能将明文表示的消息转成另外某种表示,我们还需要能将编码文本转回成明文.从明文到编码文本的转换称为"编码&qu

四则运算终极版

四则运算终极版要求: 1.生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在e1-e2的子表达式,那么结果大于等于0: 2.生成的题目中如果存在形式如e1/e2的子表达式,那么其结果应该是真分数. 3.每道题目中出现的运算符个数不超过3个,括号不做详细要求. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml

08重编终极版《东邪西毒:终极版》DVD粤语中字

1.东邪西毒].Ashes.of.Time.1994.384p.DVDRip.x264.ac3-DTMM.mkv 这个版本最清晰 ,可惜删减了,只有87分钟,粤语,1.4G. 2.东邪西毒(初始版).Ashes.Of.Time.1994.X264.AAC.D5-MINISD.lever1119.mkv 日本发行的,画质昏黄,可惜是国语的,片头日语说明,100分钟,805M. 3.[东邪西毒].Ashes.of.Time.1994.iNTERNAL.SUBBED.DVDRip.XviD-CFE.A

ucenter 单点登录,终极版

一 ,discuz ecshop  两边登陆都可以同步登陆到另一程序上,但退出则无法实现同步登陆.顺着 Ecshop 的退出流程,顺藤摸瓜找到了 lib_common.php 文件中的 uc_call 这个方法.这个方法的第二个参数 $params 的默认值是 null.而 Ecshop 注销时只传了调用 uc_client 中同步退出方法名做为一个参数的值,第二个参数使用的是默认值.而这个方法中通过 call_user_func_array($func, $params); 来调用对应的方法,

vim--vim终极配置文件之最终极版

""""""""""""""""""""""""""""""""""""""""" " A

用js制作163登陆页面终极版(写了一晚上)

用js制作163登陆页面终极版(写了一晚上),有些功能还不太完善,有兴趣的可以去自己再实现一些功能,基本上所有的功能我都实现了,只有少数的没有实现,里面还有一些正则表达式的运用,主要还是用表格设计的,没有用div,下次上传div的. 下面看HTML代码: <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>mischen

阿里正式发布《Java开发手册》终极版!

摘要: 本文讲的是阿里正式发布<Java开发手册>终极版!,别人都说我们是码农,但我们知道,自己是个艺术家.也许我们不过多在意自己的外表和穿着,但我们不羁的外表下,骨子里追求着代码的美.质量的美.而代码规约其实就是一个对美的定义. 本文讲的是阿里正式发布<Java开发手册>终极版!,别人都说我们是码农,但我们知道,自己是个艺术家.也许我们不过多在意自己的外表和穿着,但我们不羁的外表下,骨子里追求着代码的美.质量的美.而代码规约其实就是一个对美的定义. <阿里巴巴Java开发手

18.04.26 魔兽世界终极版

A:魔兽世界终极版 描述 魔兽世界的西面是红魔军的司令部,东面是蓝魔军的司令部.两个司令部之间是依次排列的若干城市,城市从西向东依次编号为1,2,3 .... N ( N <= 20 ).红魔军的司令部算作编号为0的城市,蓝魔军的司令部算作编号为N+1的城市.司令部有生命元,用于制造武士. 两军的司令部都会制造武士.武士一共有 dragon .ninja.iceman.lion.wolf 五种.每种武士都有编号.生命值.攻击力这三种属性. 双方的武士编号都是从1开始计算.红方制造出来的第 n 个