hdu4888 Redraw Beautiful Drawings 最大流+判环
Redraw Beautiful DrawingsTime Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2007 Accepted Submission(s): 447 Problem Description
Alice and Bob are playing together. Alice is crazy about art and she has visited many museums around the world. She has a good memory and she can remember all drawings she has seen.
Today Alice designs a game using these drawings in her memory. First, she matches K+1 colors appears in the picture to K+1 different integers(from 0 to K). After that, she slices the drawing into grids and there are N rows and M columns. Each grid has an integer on it(from 0 to K) representing the color on the corresponding position in the original drawing. Alice wants to share the wonderful drawings with Bob and she tells Bob the size of the drawing, the number of different colors, and the sum of integers on each row and each column. Bob has to redraw the drawing with Alice's information. Unfortunately, somtimes, the information Alice offers is wrong because of Alice's poor math. And sometimes, Bob can work out multiple different drawings using the information Alice provides. Bob gets confused and he needs your help. You have to tell Bob if Alice's information is right and if her information is right you should also tell Bob whether he can get a unique drawing. Input
The input contains mutiple testcases.
For each testcase, the first line contains three integers N(1 ≤ N ≤ 400) , M(1 ≤ M ≤ 400) and K(1 ≤ K ≤ 40). N integers are given in the second line representing the sum of N rows. M integers are given in the third line representing the sum of M columns. The input is terminated by EOF. Output
For each testcase, if there is no solution for Bob, output "Impossible" in one line(without the quotation mark); if there is only one solution for Bob, output "Unique" in one line(without the quotation mark) and output an N * M matrix in the following N lines representing Bob's unique solution; if there are many ways for Bob to redraw the drawing, output "Not Unique" in one line(without the quotation mark).
Sample Input
2 2 4
4 2 4 2 4 2 2 2 2 5 0 5 4 1 4 3 9 1 2 3 3 Sample Output
Not Unique
Impossible Unique 1 2 3 3 Author
Fudan University
Source
Recommend
|
大意:n*m的矩阵,每个格子可以是0~k,给出各行的和和各列的和,求格子数字唯一方案,或判断无解或不唯一。
题解:
最大流,每行一个点,每列一个点,起点到每行的点连流量等于这行的和的边,每列的点连流量等于这列的和的边到终点,每行的点连到每列的点流量为K的点。所有行的和不等于所有列的和 或 最大流不等于所有行的和 则无解。有解的话再判有没有环,有环说明多解,可以dfs判环。
我这题卡了好久,判环的地方怒有问题,后来我看别人代码,只用从1~nr(行数)作为起始位置就能判完,也就是从行的节点开始,如果所有节点都开始一发的话会超时……我觉得再开点东西来记忆的话应该可以更快点,日后再说吧。
日后:
有了更好的删边判环方法,具体见一道几乎相同的题的题解:http://www.cnblogs.com/yuiffy/p/3929369.html
因为要删边判环,边被删了不好输出结果,所以先记录结果再删就好啦。速度快得飞起来。
(我的网络流是n个点,下标1~n的ISAP+GAP+CUR,怕不怕)
日前代码:
- #include<cstdio>
- #include<cmath>
- #include<iostream>
- #include<cstring>
- #include<algorithm>
- #include<cmath>
- #include<map>
- #include<set>
- using namespace std;
- #define ll __int64
- #define usint unsigned int
- #define RE freopen("1002.in","r",stdin)
- #define WE freopen("1002my.out","w",stdout)
- int ans;
- int r[],co[];
- int k,nr,nc;
- int sumr,sumc;
- const int maxn=;//点数
- const int maxm=;//边数
- const int inf=0x7fffffff;//MAXINT
- struct vnode {
- int v,next;
- int cap;
- };
- int cnt,head[maxn];
- int h[maxn],g[maxn],d[maxn];//g[i]为标号为i的结点个数,h[i]为i结点的标号,d[]当前弧优化,记录当前弧
- bool found;
- int n,m,st,ed;//n个点m条边
- int augc,flow;//augc为增广路容量,flow为最大流
- vnode e[maxm];
- void add(int x,int y,int z) {
- e[cnt].v=y;
- e[cnt].cap=z;
- e[cnt].next=head[x];
- head[x]=cnt;
- cnt++;
- // if(cnt>=maxm|| x>=maxn||y>=maxn)
- // {
- // //cout<<x<<','<<y<<','<<z<<','<<cnt<<','<<head[x]<<','<<head[y]<<endl;
- // getchar();
- // }
- e[cnt].v=x;
- e[cnt].cap=;
- e[cnt].next=head[y];
- head[y]=cnt;
- cnt++;
- }
- bool walked[maxn];
- bool dfs(int x,int preE) {
- //cout<<x<<',';
- for (int i=head[x]; i!=-; i=e[i].next)//寻找容许边
- {
- if(i==(preE^))continue;
- if (e[i].cap>) { //如果残留容量大于0,如果不是直接回头
- if(walked[e[i].v])return true;
- walked[e[i].v]=true;
- if(dfs(e[i].v,i)) return true;
- walked[e[i].v]=false;
- }
- }
- //printf("(%d)out ",x);
- //getchar();
- return false;
- }
- void aug(const int &m) {
- int i,mini,minh=n-;
- int augco=augc;
- if (m==ed) { //如果当前结点为汇点
- found=true;
- flow+=augc; //增加流量
- return;
- }
- for (i=d[m]; i!=-; i=e[i].next) { //寻找容许边
- //printf("m=%d,i=%d,e[i].v=%d,e[i].cap=%d,e[i].next=%d\n",m,i,e[i].v,e[i].cap,e[i].next);
- //getchar();
- if (e[i].cap && h[e[i].v]+==h[m]) { //如果残留容量大于0,如果是容许边
- if (e[i].cap < augc) augc=e[i].cap;//如果容许边流量小于当前增广路流量 则更新增广路流量
- d[m]=i; //把i定为当前弧
- aug(e[i].v); //递归
- if (h[st]>=n) return; //GAP 如果源点距离标号大于n 则停止算法
- if (found) break; //如果找到汇点 则退出寻找
- augc=augco;//没找到就还原当前的流
- }
- }
- if (!found) { //重标号
- for (i=head[m]; i!=-; i=e[i].next) //找那个标号,这里不能用d[m]开始,不然会蛋疼
- if (e[i].cap && h[e[i].v]<minh) {
- minh=h[e[i].v];
- mini=i;
- }
- g[h[m]]--; //GAP 距离为
- if (!g[h[m]]) h[st]=n; //GAP
- h[m]=minh+;
- d[m]=mini;
- g[h[m]]++; //GAP
- } else {
- //修改残量
- e[i].cap-=augc;
- e[i^].cap+=augc;
- }
- }
- void farm() {
- int i,j,x,y,z;
- memset(head,-,sizeof(head));
- cnt=;
- n=nc+nr+;
- st=n-;
- ed=n;
- for(i=nc; i>=; i--)
- add(st,i,co[i-]);
- for(i=nr; i>=; i--)
- add(nc+i,ed,r[i-]);
- for(i=nc; i>=; i--)
- for(j=nr; j>=; j--)
- add(i,nc+j,k);
- //printf("cnt=%d\n",cnt);
- memset(h,,sizeof(h));
- memset(g,,sizeof(g));
- g[]=n;
- flow=;
- //printf("st=%d,head[st]=%d\n",st,head[st]);
- for(i=; i<=n; i++)
- d[i]=head[i];//当前弧初始化
- while(h[st]<n) {
- augc=inf;//初始化增广路容量为正无穷大
- found=false;
- aug(st);//从源点开始找
- }
- if(flow!=sumr) {ans=;return;}
- //printf("%d\n",flow);
- memset(walked,false,sizeof(walked));
- for(i=;i<=nr;i++) ///Why is nr?
- {
- //printf("start dfs(%d)\n",i);
- if(dfs(i,-)) {ans=;return;}
- }
- ans=;
- //printf("%d\n",flow);
- }
- int main() {
- //RE;
- //WE;
- int i,j;
- while(scanf("%d%d%d",&nr,&nc,&k)!=EOF) {
- sumr=;sumc=;
- for(i=; i<nr; i++)
- {
- scanf("%d",&r[i]);
- sumr+=r[i];
- }
- for(i=; i<nc; i++)
- {
- scanf("%d",&co[i]);
- sumc+=co[i];
- }
- ans=;
- if(sumr==sumc)farm();
- if(ans==) printf("Impossible\n");
- else if(ans!=) {
- printf("Not Unique\n");
- // for(i=1; i<=nr; i++) {
- // for(j=head[nc+i]; j!=-1; j=e[j].next)
- // {
- // if(e[j].v==ed)continue;
- // printf("%d ",e[j].cap);
- // }
- // puts("");
- // }
- } else {
- printf("Unique\n");
- for(i=; i<=nr; i++) {
- for(j=head[nc+i]; j!=-; j=e[j].next) {
- if(e[j].v==ed)continue;
- printf("%d",e[j].cap);
- int thenext=e[j].next;
- while(thenext!=-&&e[thenext].v==ed)thenext=e[thenext].next;
- if(thenext!=-)putchar(' ');
- }
- puts("");
- }
- }
- }
- //cout<<"end";
- return ;
- }
日后代码:
- //#pragma comment(linker, "/STACK:102400000,102400000")
- #include<cstdio>
- #include<cmath>
- #include<iostream>
- #include<cstring>
- #include<algorithm>
- #include<cmath>
- #include<map>
- #include<set>
- #include<stack>
- #include<queue>
- using namespace std;
- #define ll long long
- #define usll unsigned ll
- #define mz(array) memset(array, 0, sizeof(array))
- #define minf(array) memset(array, 0x3f, sizeof(array))
- #define REP(i,n) for(i=0;i<(n);i++)
- #define FOR(i,x,n) for(i=(x);i<=(n);i++)
- #define RD(x) scanf("%d",&x)
- #define RD2(x,y) scanf("%d%d",&x,&y)
- #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- #define WN(x) prllf("%d\n",x);
- #define RE freopen("1002.in","r",stdin)
- #define WE freopen("1002testout.txt","w",stdout)
- #define mp make_pair
- #define pb push_back
- int ans;
- int r[],co[];
- int k,nr,nc;
- int sumr,sumc;
- const int maxn=;//点数
- const int maxm=;//边数
- const int inf=0x7fffffff;//MAXINT
- struct vnode {
- int v,next;
- int cap;
- };
- int cnt,head[maxn];
- int h[maxn],g[maxn],d[maxn];//g[i]为标号为i的结点个数,h[i]为i结点的标号,d[]当前弧优化,记录当前弧
- bool found;
- int n,m,st,ed;//n个点m条边
- int augc,flow;//augc为增广路容量,flow为最大流
- vnode e[maxm];
- int an[maxn][maxn];
- void add(int x,int y,int z) {
- e[cnt].v=y;
- e[cnt].cap=z;
- e[cnt].next=head[x];
- head[x]=cnt;
- cnt++;
- // if(cnt>=maxm|| x>=maxn||y>=maxn)
- // {
- // //cout<<x<<','<<y<<','<<z<<','<<cnt<<','<<head[x]<<','<<head[y]<<endl;
- // getchar();
- // }
- e[cnt].v=x;
- e[cnt].cap=;
- e[cnt].next=head[y];
- head[y]=cnt;
- cnt++;
- }
- bool walked[maxn];
- bool dfs(const int &x,const int &prex) {///深搜判环
- int biu=-;
- walked[x]=true;
- for (int i=head[x]; i!=-; i=e[i].next) {
- if(e[i].v==prex) {
- biu=i;
- continue;
- }
- if (e[i].cap>) {
- if(walked[e[i].v]) return true;
- if(dfs(e[i].v,x)) return true;
- }
- if(biu==-) head[x]=e[i].next;///删边,因为走了这条边却没发现环
- else e[biu].next=e[i].next;
- biu=i;
- }
- walked[x]=false;
- return false;
- }
- void aug(const int &m) {
- int i,mini,minh=n-;
- int augco=augc;
- if (m==ed) { //如果当前结点为汇点
- found=true;
- flow+=augc; //增加流量
- return;
- }
- for (i=d[m]; i!=-; i=e[i].next) { //寻找容许边
- //printf("m=%d,i=%d,e[i].v=%d,e[i].cap=%d,e[i].next=%d\n",m,i,e[i].v,e[i].cap,e[i].next);
- //getchar();
- if (e[i].cap && h[e[i].v]+==h[m]) { //如果残留容量大于0,如果是容许边
- if (e[i].cap < augc) augc=e[i].cap;//如果容许边流量小于当前增广路流量 则更新增广路流量
- d[m]=i; //把i定为当前弧
- aug(e[i].v); //递归
- if (h[st]>=n) return; //GAP 如果源点距离标号大于n 则停止算法
- if (found) break; //如果找到汇点 则退出寻找
- augc=augco;//没找到就还原当前的流
- }
- }
- if (!found) { //重标号
- for (i=head[m]; i!=-; i=e[i].next) //找那个标号,这里不能用d[m]开始,不然会蛋疼
- if (e[i].cap && h[e[i].v]<minh) {
- minh=h[e[i].v];
- mini=i;
- }
- g[h[m]]--; //GAP 距离为
- if (!g[h[m]]) h[st]=n; //GAP
- h[m]=minh+;
- d[m]=mini;
- g[h[m]]++; //GAP
- } else {
- //修改残量
- e[i].cap-=augc;
- e[i^].cap+=augc;
- }
- }
- void farm() {
- int i,j,x,y,z;
- memset(head,-,sizeof(head));
- cnt=;
- n=nc+nr+;
- st=n-;
- ed=n;
- for(i=nc; i>=; i--)
- add(st,i,co[i-]);
- for(i=nr; i>=; i--)
- add(nc+i,ed,r[i-]);
- for(i=nc; i>=; i--)
- for(j=nr; j>=; j--)
- add(i,nc+j,k);
- //printf("cnt=%d\n",cnt);
- memset(h,,sizeof(h));
- memset(g,,sizeof(g));
- g[]=n;
- flow=;
- //printf("st=%d,head[st]=%d\n",st,head[st]);
- for(i=; i<=n; i++)
- d[i]=head[i];//当前弧初始化
- while(h[st]<n) {
- augc=inf;//初始化增广路容量为正无穷大
- found=false;
- aug(st);//从源点开始找
- }
- if(flow!=sumr) {
- ans=;
- return;
- }
- //printf("%d\n",flow);
- for(i=; i<=nr; i++) {
- int k=;
- for(j=head[nc+i]; j!=-; j=e[j].next) {
- if(e[j].v==ed)continue;
- an[i][k++]=e[j].cap;
- int thenext=e[j].next;
- while(thenext!=-&&e[thenext].v==ed)thenext=e[thenext].next;
- }
- }
- memset(walked,false,sizeof(walked));
- for(i=nr; i>=; i--) { ///Why is nr?
- //printf("start dfs(%d)\n",i);
- if(dfs(i,-)) {
- ans=;
- return;
- }
- }
- ans=;
- //printf("%d\n",flow);
- }
- int main() {
- //RE;
- //WE;
- int i,j;
- while(scanf("%d%d%d",&nr,&nc,&k)!=EOF) {
- sumr=;
- sumc=;
- for(i=; i<nr; i++) {
- scanf("%d",&r[i]);
- sumr+=r[i];
- }
- for(i=; i<nc; i++) {
- scanf("%d",&co[i]);
- sumc+=co[i];
- }
- ans=;
- if(sumr==sumc)farm();
- if(ans==) printf("Impossible\n");
- else if(ans!=) {
- printf("Not Unique\n");
- // for(i=1; i<=nr; i++) {
- // for(j=head[nc+i]; j!=-1; j=e[j].next)
- // {
- // if(e[j].v==ed)continue;
- // printf("%d ",e[j].cap);
- // }
- // puts("");
- // }
- } else {
- printf("Unique\n");
- for(i=; i<=nr; i++) {
- if(nc>=)printf("%d",an[i][]);
- for(j=; j<=nc; j++) {
- printf(" %d",an[i][j]);
- }
- puts("");
- }
- }
- }
- //cout<<"end";
- return ;
- }
hdu4888 Redraw Beautiful Drawings 最大流+判环的更多相关文章
- HDU4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3)
Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- HDU4888 Redraw Beautiful Drawings(最大流唯一性判定:残量网络删边判环)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4888 Description Alice and Bob are playing toget ...
- hdu 4888 Redraw Beautiful Drawings(最大流,判环)
pid=4888">http://acm.hdu.edu.cn/showproblem.php?pid=4888 加入一个源点与汇点,建图例如以下: 1. 源点 -> 每一行相应 ...
- hdu4888 Redraw Beautiful Drawings(最大流)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4888 题意:给一个矩阵没行的和和每列的和,问能否还原矩阵,如果可以还原解是否唯一,若唯一输出该矩阵. ...
- hdu 4888 Redraw Beautiful Drawings 最大流
好难好难,将行列当成X和Y,源汇点连接各自的X,Y集,容量为行列的和,相当于从源点流向每一行,然后分配流量给每一列,最后流入汇点,这样执意要推断最后是否满流,就知道有没有解,而解就是每一行流向每一列多 ...
- hdu4888 Redraw Beautiful Drawings
14更多学校的第二个问题 网络流量 分别以行,列作为结点建图 i行表示的结点到j列表示的结点的流量便是(i, j)的值 跑遍最大流 若满流了便是有解 推断是否unique 就是在残余网络 ...
- Redraw Beautiful Drawings(hdu4888)网络流+最大流
Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/O ...
- HDU Redraw Beautiful Drawings 推断最大流是否唯一解
点击打开链接 Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 ...
- 【HDU】4888 Redraw Beautiful Drawings 网络流【推断解是否唯一】
传送门:pid=4888">[HDU]4888 Redraw Beautiful Drawings 题目分析: 比赛的时候看出是个网络流,可是没有敲出来.各种反面样例推倒自己(究其原因 ...
随机推荐
- Leetcode Perfect Square
这道题首先想到的算法是DP.每个perfect square number对应的解都是1.先生成一个n+1长的DP list.对于每个i,可以用dp[i] = min(dp[j] + dp[i-j], ...
- XCode显示iOS Simulators时不显示系统版本号并出现Identifier(UUID)
如果出现如下的显示问题,说明你添加了多个相同系统版本的iOS Simulators: 打开Windows->Devices,查看已经出现了相同版本的模拟器: 那么我们删除一些相同的模拟器,即可解 ...
- Linux Crontab 定时任务 命令详解
一. Crontab 介绍 crontab命令的功能是在一定的时间间隔调度一些命令的执行. 1.1 /etc/crontab 文件 在/etc目录下有一个crontab文件,这里存放有系统运行的一些调 ...
- poj3484 Showstopper 二分
题目地址 二分用的很是巧妙!关键是抽象出问题本质. #include <cstdio> #include <string> #include <cstring> ; ...
- Python 操作 mongodb 数据库
原文地址:https://serholiu.com/python-mongodb 这几天在学习Python Web开发,于 是做准备做一个博客来练练手,当然,只是练手的,博客界有WordPress这样 ...
- AngularJs ngApp、ngBind、ngBindHtml、ngNonBindable
ngApp 使用这个指令自动启动一个AngularJS应用.ngApp指令指定了应用程序的根节点,通常会将ngApp放置在网页的根节点如<body>或<html >标签的. 格 ...
- 区别 Jquery对象和Dom对象
在讨论之前,先约定好定义变量的风格. 如果获取的对象是jQuery对象,那么在变量前加上$,例如: var $variable = jQuery对象; 如果获取的是DOM对象,则定义如下: var v ...
- hihoCoder1284机会渺茫(唯一分解定理 + 约分)
题目链接 #1284 : 机会渺茫 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi最近在追求一名学数学的女生小Z.小Z其实是想拒绝他的,但是找不到好的说辞,于是提出 ...
- spring--学习之IOC DI
2.1.1 IoC是什么 Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器 ...
- phpcms后台获取当前登录账号的数据
$amdinid=$_SESSION['userid'];$infoadmin=$this->admin->get_one(array('userid'=>$amdinid)); v ...