hdu 4888 Redraw Beautiful Drawings 2014多校三补题 网络流

题目链接:hdu 4888

        给定一个N*M的矩阵,已知每行和以及每列和,每个元素(大于等于0)的上限值K,问这样的矩阵是否存在,若存在,判断是否唯一,唯一则输出

        网络流,从源点向行带表的点建边,流量为行和,列代表的边向汇点建边,流量为列和,每行向每列建边,流量为K,求源点到汇点的最大流,若是满流,则说明矩阵存在。然后判断残留网络是否存在环,若存在则说明有多解

/******************************************************
 * File Name:   4888.cpp
 * Author:      kojimai
 * Creater Time:2014年08月22日 星期五 00时58分29秒
 ******************************************************/
/*
 *网络流,求最大流是否满流
 *然后判断残留网络是否存在环
 */
#include<queue>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,K;
#define FFF 404
int row[FFF],col[FFF];
int map[FFF][FFF];
struct node
{
	int u,v,f,next;
}p[400010];
int first[900],e,cur[900],dis[900],que[2100];
void addedge(int u,int v,int c)
{
	p[e].u=u;p[e].v=v;p[e].f=c;p[e].next=first[u];first[u]=e++;
	p[e].u=v;p[e].v=u;p[e].f=0;p[e].next=first[v];first[v]=e++;
}
bool bfs(int s,int t)//找增广路径
{
	memset(dis,-1,sizeof(dis));
	dis[s]=0;
	queue<int> q;
	q.push(s);
	while(!q.empty())
	{
		int now=q.front();q.pop();
		for(int k=first[now];~k;k=p[k].next)
		{
			if(p[k].f>0&&dis[p[k].v]==-1)
			{
				dis[p[k].v]=dis[now]+1;
				if(p[k].v==t)
					return true;
				q.push(p[k].v);
			}
		}
	}
	return false;
}
int dinic(int s,int t)//dinic求最大流
{
	//cout<<"s="<<s<<" t="<<t<<endl;
	int ans=0;
	while(bfs(s,t))
	{
		memcpy(cur,first,sizeof(first));
		int now=s,tail=0;
		while(true)
		{
			int k;
			if(now==t)
			{
				int flow=23333333,fir;
				for(int i=0;i<tail;i++)
				{
					if(p[que[i]].f<flow)
					{
						fir=i;
						flow=p[que[i]].f;
					}
				}
				for(int i=0;i<tail;i++)
				{
					p[que[i]].f-=flow;
					p[que[i]^1].f+=flow;
				}
				ans+=flow;
				tail=fir;
				now=p[que[fir]].u;
			}
			for(k=cur[now];~k;cur[now]=k=p[k].next)
			{
				if(p[k].f&&dis[now]+1==dis[p[k].v])
					break;
			}
			if(cur[now]!=-1)
			{
				que[tail++]=cur[now];
				now=p[cur[now]].v;
			}
			else
			{
				if(tail==0)
					break;
				dis[now]=-1;
				now=p[que[--tail]].u;
			}
		}
	}
	return ans;
}
int vis[FFF*2];
/*int dfn[FFF*2],low[FFF*2],c[FFF*2],snum,dnum,stack[FFF*2];
bool tarjan(int s,int last)//tarjan找环不可行,因为不能算两点的环,容易出错
{
	dfn[s]=low[s]=dnum++;
	stack[snum++]=s;vis[s]=true;
	for(int k=first[s];k!=-1;k=p[k].next)
	{
		//cout<<" s="<<s<<" k="<<k<<" v="<<p[k].v<<" f="<<p[k].f<<endl;
		if(p[k].f>0&&k!=last)
		{
			if(!dfn[p[k].v])
			{
				if(tarjan(p[k].v,s))
					return true;
				low[s]=min(low[s],low[p[k].v]);
			}
			else if(vis[p[k].v])
			{
				low[s]=min(low[s],dfn[p[k].v]);
			}
		}
	}
	//cout<<"s="<<s<<" low="<<low[s]<<" dfn="<<dfn[s]<<endl;
	if(low[s]==dfn[s])
	{
		int y=stack[--snum];
		//cout<<"s="<<s<<" y="<<y<<endl;
		vis[y]=false;
		if(y!=s)
			return true;
	}
	return false;
}*/
bool dfs(int s,int last)//找环
{
	for(int k=first[s];~k;k=p[k].next)
	{
		if(p[k].v==last)continue;
		if(p[k].f)
		{
			if(vis[p[k].v])return true;
			vis[p[k].v]=true;
			if(dfs(p[k].v,s))return true;
			vis[p[k].v]=false;
		}
	}
	return false;
}
void out()
{
	printf("Unique\n");
	memset(map,0,sizeof(map));
	for(int i=1;i<=n;i++)
	{
		for(int k=first[i];~k;k=p[k].next)
		{
			if(p[k].v>n&&p[k].v<=n+m)
				map[i][p[k].v-n]=K-p[k].f;//用流量上限减去残留网络的值,即为当前的流量
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(j==m)
				printf("%d\n",map[i][j]);
			else
				printf("%d ",map[i][j]);
		}
	}
	return;
}
int main()
{
	//freopen("out.out","w",stdout);
	while(~scanf("%d%d%d",&n,&m,&K))
	{
		int alla=0,allb=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&row[i]);
			alla+=row[i];
		}
		for(int i=1;i<=m;i++)
		{
			scanf("%d",&col[i]);
			allb+=col[i];
		}
		if(alla!=allb)
			printf("Impossible\n");
		else
		{
			e=0;
			memset(first,-1,sizeof(first));
			for(int i=1;i<=n;i++)
			{
				addedge(0,i,row[i]);
			}
			for(int i=1;i<=m;i++)
				addedge(i+n,n+m+1,col[i]);
			for(int i=1;i<=n;i++)
			{
				for(int j=1;j<=m;j++)
					addedge(i,j+n,K);
			}
			int sum=dinic(0,n+m+1);
			if(sum!=alla)
				printf("Impossible\n");
			else
			{
				//snum=1;dnum=1;
				memset(vis,false,sizeof(vis));
				bool flag=false;
				//memset(dfn,0,sizeof(dfn));
				//memset(low,0,sizeof(low));
				for(int i=n;i>=1&&!flag;i--)
				{
					if(!vis[i])
						flag=dfs(i,-1);
				}
				if(flag)
					printf("Not Unique\n");
				else
					out();
			}
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
疫情居家办公系统管理系统按照操作主体分为管理员和用户。管理员的功能包括办公设备管理、部门信息管理、字典管理、公告信息管理、请假信息管理、签到信息管理、留言管理、外出报备管理、薪资管理、用户管理、公司资料管理、管理员管理。用户的功能等。该系统采用了MySQL数据库,Java语言,Spring Boot框架等技术进行编程实现。 疫情居家办公系统管理系统可以提高疫情居家办公系统信息管理问题的解决效率,优化疫情居家办公系统信息处理程,保证疫情居家办公系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理疫情居家办公系统信息,包括外出报备管理,培训管理,签到管理,薪资管理等,可以管理公告。 外出报备管理界面,管理员在外出报备管理界面中可以对界面中显示,可以对外出报备信息的外出报备状态进行查看,可以添加新的外出报备信息等。签到管理界面,管理员在签到管理界面中查看签到种类信息,签到描述信息,新增签到信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值