1. 程式人生 > >【BZOJ 4500 矩陣】

【BZOJ 4500 矩陣】

約束 brush turn 限制 href first des col 三元

Time Limit: 1 Sec Memory Limit: 256 MB
Submit: 390 Solved: 217
[
Submit][Status][Discuss]

Description

有一個n*m的矩陣,初始每個格子的權值都為0,可以對矩陣執行兩種操作:

1. 選擇一行, 該行每個格子的權值加1或減1。

2. 選擇一列, 該列每個格子的權值加1或減1。

現在有K個限制,每個限制為一個三元組(x,y,c),代表格子(x,y)權值等於c。問是否存在一個操作序列,使得操作完後的矩陣滿足所有的限制。如果存在輸出”Yes”,否則輸出”No”。

Input

先輸入一個T(T <= 5)代表輸入有T組數據,每組數據格式為:

第一行三個整數n, m, k (1 <= n, m,k <= 1000)。

接下來k行,每行三個整數x, y, c。

Output

對於每組數據,輸出Yes或者No。

Sample Input

2
2 2 4
1 1 0
1 2 0
2 1 2
2 2 2
2 2 4
1 1 0
1 2 0
2 1 2
2 2 1

Sample Output

Yes
No

HINT

Source

【題解】

①行列差分約束。

②每個行每個列看做一個點。

③建立超級源點保證圖連通,進行一次SPFA即可解決。

#include<queue>
#include<stdio.h>
#define inf 1000000007
#define go(i,a,b) for(int i=a;i<=b;i++)
#define fo(i,a,x) for(int i=a[x],v=e[i].v;i;i=e[i].next,v=e[i].v)
const int N=2010;
struct E{int v,next,w;}e[N<<2];
int T,n,m,K,head[N],k,x,y,v,S,d[N],vis[N];bool inq[N],bad;
void ADD(int u,int v,int w){e[k]=(E){v,head[u],w};head[u]=k++;}

bool SPFA()
{
	std::queue<int>q;d[S]=0;
	while(!q.empty())q.pop();q.push(S);int u;
	while(!q.empty())
	{
		inq[u=q.front()]=0;q.pop();
		fo(i,head,u)if(d[u]+e[i].w<d[v])
		{
			d[v]=d[u]+e[i].w;	
			if((++vis[v])>(n+m))return 0;	
			if(!inq[v])inq[v]=1,q.push(v);
		}
	}
	return 1;
}

int main()
{
	scanf("%d",&T);
	while(T--&&scanf("%d%d%d",&n,&m,&K))
	{
		go(i,0,n+m)d[i]=inf,head[i]=inq[i]=vis[i]=0;bad=0;k=1;
		go(i,1,K)scanf("%d%d%d",&x,&y,&v),ADD(x,y+n,v),ADD(y+n,x,-v);
		go(i,1,n+m)ADD(S,i,0);puts(SPFA()?"Yes":"No");
	}
	return 0;
}//Paul_Guderian

.

【BZOJ 4500 矩陣】