bzoj4500 矩陣 差分約束系統
阿新 • • 發佈:2018-11-05
Description
有一個n*m的矩陣,初始每個格子的權值都為0,可以對矩陣執行兩種操作:
1.選擇一行,該行每個格子的權值加1或減1。
2.選擇一列,該列每個格子的權值加1或減1。
現在有K個限制,每個限制為一個三元組(x,y,c),代表格子(x,y)權值等於c。
問是否存在一個操作序列,使得操作完後的矩陣滿足所有的限制。
如果存在輸出”Yes”,否則輸出”No”。
先輸入一個T(T <= 5)代表輸入有T組資料,每組資料格式為:
第一行三個整數n, m, k (1 <= n, m,k <= 1000)。
接下來k行,每行三個整數x, y, c。
Solution
我是誰,差分約束是啥,這是哪
考慮記行操作為x[],列操作為y[],那麼一個限制等價於x[i]+y[j]=c
轉換一下就是x[i]-(-y[j])<=c,-y[j]-x[i]<=-c
注意到這個和最短路的鬆弛條件很像,即最短路上滿足dis[y]-dis[x]<=w[x][y]
那麼對於這種形式的限制連邊y[j]到x[i]跑最短路就行了。不需要輸出方案就判環嘛
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int N=4005;
const int E=10005;
struct edge {int y,w,next;} e[E];
bool vis[N];
int dis[N],cnt[N];
int ls[N],edCnt;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=( ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y,int w) {
e[++edCnt]=(edge) {y,w,ls[x]}; ls[x]=edCnt;
}
bool spfa(int st) {
std:: queue <int> que;
vis[st]=true; dis[st]=0;
bool ret=false;
for (que.push(st);!que.empty();) {
int now=que.front(); que.pop();
if (++cnt[now]==1000) return true;
for (int i=ls[now];i;i=e[i].next) {
if (dis[now]+e[i].w<dis[e[i].y]) {
dis[e[i].y]=dis[now]+e[i].w;
if (!vis[e[i].y]) {
que.push(e[i].y); vis[e[i].y]=true;
}
}
} vis[now]=false;
}
return false;
}
int main(void) {
for (int T=read();T--;) {
edCnt=0; fill(ls,0); fill(vis,0);
int n=read(),m=read(),k=read();
rep(i,1,k) {
int x=read(),y=read(),c=read();
add_edge(y+n,x,c);
add_edge(x,y+n,-c);
}
fill(dis,63); fill(cnt,0);
bool flag=false;
rep(i,1,n+m) if (dis[i]==dis[0]) {
flag|=spfa(i);
}
flag?puts("No"):puts("Yes");
}
return 0;
}