POJ - 2396 Budget && 洛谷P4311 士兵占领【有上下界网络流】

POJ - 2396 Budget

Time limit3000 ms
Memory limit65536 kB

We are supposed to make a budget proposal for this multi-site competition. The budget proposal is a matrix where the rows represent different kinds of expenses and the columns represent different sites. We had a meeting about this, some time ago where we discussed the sums over different kinds of expenses and sums over different sites. There was also some talk about special constraints: someone mentioned that Computer Center would need at least 2000K Rials for food and someone from Sharif Authorities argued they wouldn’t use more than 30000K Rials for T-shirts. Anyway, we are sure there was more; we will go and try to find some notes from that meeting.

And, by the way, no one really reads budget proposals anyway, so we’ll just have to make sure that it sums up properly and meets all constraints.

Input

The first line of the input contains an integer N, giving the number of test cases. The next line is empty, then, test cases follow: The first line of each test case contains two integers, m and n, giving the number of rows and columns (m <= 200, n <= 20). The second line contains m integers, giving the row sums of the matrix. The third line contains n integers, giving the column sums of the matrix. The fourth line contains an integer c (c < 1000) giving the number of constraints. The next c lines contain the constraints. There is an empty line after each test case.

Each constraint consists of two integers r and q, specifying some entry (or entries) in the matrix (the upper left corner is 1 1 and 0 is interpreted as “ALL”, i.e. 4 0 means all entries on the fourth row and 0 0 means the entire matrix), one element from the set {<, =, >} and one integer v, with the obvious interpretation. For instance, the constraint 1 2 > 5 means that the cell in the 1st row and 2nd column must have an entry strictly greater than 5, and the constraint 4 0 = 3 means that all elements in the fourth row should be equal to 3.

Output

For each case output a matrix of non-negative integers meeting the above constraints or the string “IMPOSSIBLE” if no legal solution exists. Put one empty line between matrices.


题目大意

给定一些限制条件,要求构造符合条件的矩阵
每个条件形如每一行的和,每一列的和,或某个单元格得值取值范围


题目分析

有上下界最小流的经典题
每行看作一个点 ( 1 − n ) (1-n) (1n),每列看作一个点 ( n + 1 (n+1 (n+1~ n + m ) n+m) n+m)
建立虚拟源汇点
虚拟源点向代表每行的点连边,下界、上界都为限定的行和
代表每列的点向虚拟汇点连边,下界、上界都为限定的列和

根据题目要求记录下每个单元格的限制
对于 ( i , j ) (i,j) (i,j)这个单元格,设其下限为 l l l,上限为 r r r
连边 i , j + n i,j+n i,j+n下界为 l l l上界为 r r r

按照有上下界网络流构图跑ss到tt(超级源汇)的最大流,即得到了一种可行补流方案
之后每条代表单元格限制的边上的流量+这个单元格的下限 即为该可行方案中此单元格的数值

(这题十分考码力啊=_=,如果对这题构图方式还不熟可以先做下面那道)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long lt;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int inf=1128481603;
const int maxN=310;
const int maxM=100010;
int T,n,m,k;
struct node{int v,f,nxt;}E[maxM];
int head[maxN],tot=1;
int deg[maxN],lev[maxN];
int low[maxN][maxN],up[maxN][maxN];
int rem[maxN][maxN],judge;

void add(int u,int v,int f)
{
    E[++tot].nxt=head[u];
    E[tot].v=v; E[tot].f=f;
    head[u]=tot; 
}

int bfs(int s,int t)
{
    queue<int> q; q.push(s);
    memset(lev,-1,sizeof(lev)); lev[s]=0;
 
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=E[i].nxt)
        {
            int v=E[i].v;
            if(lev[v]==-1&&E[i].f)
            {
                lev[v]=lev[u]+1;
                if(v==t) return 1;
                q.push(v);
            }
        }
    }
    return 0;
}
 
int dfs(int u,int cap,int t)
{
    if(u==t) return cap;
    int flow=cap;
    for(int i=head[u];i;i=E[i].nxt)
    {
        int v=E[i].v;
        if(lev[v]==lev[u]+1&&flow&&E[i].f)
        {
            int f=dfs(v,min(flow,E[i].f),t);
            E[i].f-=f; E[i^1].f+=f; 
            flow-=f;
        }
    }
    return cap-flow;
}

int dicnic(int s,int t)
{
    int maxf=0;
    while(bfs(s,t)) maxf+=dfs(s,inf,t);
    return maxf;
}

void init()
{
	judge=0;
	memset(head,0,sizeof(head)); tot=1;
	memset(deg,0,sizeof(deg));
	memset(low,0,sizeof(low));
	memset(up,67,sizeof(up));
}

void check(int x,int y,char ss,int val)
{
	if(ss=='=') {
        if(val>up[x][y] || val<low[x][y]) judge=1;
        up[x][y]=low[x][y]=val;
	}
	else if(ss=='<') 
	{
		if(val<=low[x][y]) judge=1;
		up[x][y]=min(up[x][y],val-1);
	}
    else if(ss=='>') 
	{
		if(val>=up[x][y]) judge=1;
		low[x][y]=max(low[x][y],val+1);
	}
}

void work(int x,int y,char ss,int val)
{
	if(x&&y) check(x,y,ss,val);
	else if(x==0&&y==0)
	{
		for(int i=1;i<=n;++i)
		{
			if(judge) break;
			for(int j=1;j<=m;++j)
			{
				if(judge) break; 
				check(i,j,ss,val);
			}
		}
	}
	else if(x!=0&&y==0)
	{
		for(int j=1;j<=m;++j){
			if(judge) break;
			check(x,j,ss,val);
		}
	}
	else if(x==0&&y!=0)
	{
		for(int i=1;i<=n;++i){
			if(judge) break; 
			check(i,y,ss,val);
		}
	}
}

int main()
{
    T=read();
    for(int cs=1;cs<=T;++cs)
    {
    	if(cs!=1) printf("\n"); init();
    	n=read(); m=read();
    	
    	int s=n+m+1,t=s+1;
    	for(int i=1;i<=n;++i)
    	{
        	int l=read(),r=l;
        	add(s,i,r-l); add(i,s,0);
        	deg[s]-=l; deg[i]+=l ;
    	}
    	for(int i=1;i<=m;++i)
    	{
    		int l=read(),r=l;
        	add(i+n,t,r-l); add(t,i+n,0);
        	deg[i+n]-=l; deg[t]+=l;
    	}
		
		k=read();
		for(int l=1;l<=k;++l)
		{
			int x=read(),y=read();
			char ss[2]; scanf("%s",&ss);
			int val=read();
			
			if(judge) continue;
			work(x,y,ss[0],val);
		}
		
		for(int i=1;i<=n;++i)
		{
			if(judge) break;
			for(int j=1;j<=m;++j)
			{
				if(judge) break;
				int l=low[i][j],r=up[i][j];
				if(low[i][j]>up[i][j]) judge=1;
				add(i,j+n,r-l); add(j+n,i,0);
				rem[i][j]=tot;
				deg[i]-=l; deg[j+n]+=l;
			}
		}
		
		if(judge){ printf("IMPOSSIBLE\n"); continue;}
		
		int ss=n+m+3,tt=ss+1,sum=0;
    	for(int i=1;i<=t;++i)
    	{
        	if(deg[i]>0) add(ss,i,deg[i]),add(i,ss,0),sum+=deg[i];
        	else if(deg[i]<0) add(i,tt,-deg[i]),add(tt,i,0);
    	}
    	add(t,s,inf); add(s,t,0);
    
		int maxf=dicnic(ss,tt);
		if(sum!=maxf) printf("IMPOSSIBLE\n");
		else{
			for(int i=1;i<=n;++i)
			{
				for(int j=1;j<=m;++j)
				printf("%d ",E[rem[i][j]].f+low[i][j]);
				printf("\n");
			}
		}
	}
	return 0;
}

洛谷P4311 士兵占领

时空限制 1000ms / 128MB

题目描述

有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。

输入格式:

第一行两个数M, N, K分别表示棋盘的行数,列数以及士兵的个数。 第二行有M个数表示Li。 第三行有N个数表示Ci。 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍。

输出格式:

输出一个数表示最少需要使用的士兵个数。如果无论放置多少个士兵都没有办法占领整个棋盘,输出”JIONG!” (不含引号)

说明

M, N <= 100, 0 <= K <= M * N


和上题一样的套路
虚拟源点向每个行点连边,下界为给定下界,上界为m
每个列点向虚拟汇点连边,下界为给定下界,上界为n

每个没有障碍的格子,按照上述方法连边,下界为0,上界为1
跑s到t(虚拟源汇)的最小流即为答案


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long lt;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int inf=1128481603;
const int maxN=410;
const int maxM=100010;
int n,m,k;
struct node{int v,f,nxt;}E[maxM];
int head[maxN],tot=1;
int rem[maxN][maxN];
int deg[maxN],lev[maxN];

void add(int u,int v,int f)
{
    E[++tot].nxt=head[u];
    E[tot].v=v; E[tot].f=f;
    head[u]=tot; 
}

int bfs(int s,int t)
{
    queue<int> q; q.push(s);
    memset(lev,-1,sizeof(lev)); lev[s]=0;
 
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=E[i].nxt)
        {
            int v=E[i].v;
            if(lev[v]==-1&&E[i].f)
            {
                lev[v]=lev[u]+1;
                if(v==t) return 1;
                q.push(v);
            }
        }
    }
    return 0;
}
 
int dfs(int u,int cap,int t)
{
    if(u==t) return cap;
    int flow=cap;
    for(int i=head[u];i;i=E[i].nxt)
    {
        int v=E[i].v;
        if(lev[v]==lev[u]+1&&flow&&E[i].f)
        {
            int f=dfs(v,min(flow,E[i].f),t);
            E[i].f-=f; E[i^1].f+=f; 
            flow-=f;
        }
    }
    return cap-flow;
}

int dicnic(int s,int t)
{
    int maxf=0;
    while(bfs(s,t)) maxf+=dfs(s,inf,t);
    return maxf;
}

int main()
{
    n=read();m=read();k=read();
    int s=n+m+1,t=s+1;
    
    for(int i=1;i<=n;++i)
    {
        int l=read(),r=m;
        add(s,i,r-l); add(i,s,0);
        deg[s]-=l; deg[i]+=l ;
    }
    for(int i=1;i<=m;++i)
    {
    	int l=read(),r=n;
        add(i+n,t,r-l); add(t,i+n,0);
        deg[i+n]-=l; deg[t]+=l;
    }
    
    for(int i=1;i<=k;++i) 
    {
    	int x=read(),y=read();
    	rem[x][y]=1;
    } 
    
    
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    if(!rem[i][j]) 
    add(i,j+n,1),add(j+n,i,0);
    
    int ss=n+m+3,tt=ss+1,sum=0;
    for(int i=1;i<=t;++i)
    {
        if(deg[i]>0) add(ss,i,deg[i]),add(i,ss,0),sum+=deg[i];
        else if(deg[i]<0) add(i,tt,-deg[i]),add(tt,i,0);
    }
    add(t,s,inf); add(s,t,0);
    
    int maxf=dicnic(ss,tt);
    if(maxf!=sum) printf("JIONG");
    else{
    	int ans=E[tot].f;
    	head[t]=E[head[t]].nxt;
    	head[s]=E[head[s]].nxt;
    	printf("%d",ans-dicnic(t,s));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值