您的位置:首页 > Web前端

HDU 4598 Difference 差分约束 + 判奇圈

2015-08-18 21:29 357 查看
题意:给你一个无向图 这个图是difference的如果存在一个正实数T使得图中所有的点的绝对值|ai|<T 并且点i j构成一条边当且仅当|ai-aj|>=T 问你是否存在一个这样的图

思路:一般见到不等式就要考虑考虑差分约束了 观察这个题的条件发现 每个点的绝对值都小于T 但是两个点的差值的绝对值却能够大于T 这只能是一种情况 那就是两个点一正一负 也就是要对其进行二分染色 如果存在奇环 则一定不存在这种图 还有就是这个题存在一个隐含的条件:i j构成一条边当且仅当|ai-aj|>=T 这句话的言外之意是 如果i j不构成边 则|ai-aj|<T 这个条件很难被发现- - 至于如何建图 如果i->j有一条边并且i为正 即ai - aj >= T 变形得 aj - ai <= -T 如果不存在i->j的边且i为正
则 ai - aj < T 变形得 ai - aj <= T-1 其余情况雷同 然后建图判断是否有负环即可

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define bug puts("bug")

const int maxn = 300 + 10;
const int INF = 1e9;
const int maxe = 50000;
const int T = 1000;

int n;
int g[maxn][maxn];
int STACK[maxn], top;
int dist[maxn], cnt[maxn], vis[maxn];
char G[maxn][maxn];
int color[maxn];

struct Edge{
int v, d;
int next;
Edge(int v = 0, int d = 0, int next = 0) : v(v), d(d), next(next) {}
};

int Head[maxn], cntE;
Edge edge[maxe];

void init(){
memset(Head, -1, sizeof(Head));
memset(vis, 0, sizeof(vis));
memset(cnt, 0, sizeof(cnt));
memset(color, 0, sizeof(color));
cntE = 0;
top = 0;
}

void add(int u, int v, int d){
edge[cntE] = Edge(v, d, Head[u]);
Head[u] = cntE++;
}

bool spfa(int s){
for(int i = 0; i <= n; i++) dist[i] = INF;
dist[s] = 0;
cnt[s] = vis[s] = 1;
STACK[top++] = s;
while(top){
int u = STACK[--top];
vis[u] = 0;
for(int i = Head[u]; ~i; i = edge[i].next){
int v = edge[i].v;
if(dist[v] > dist[u] + edge[i].d){
dist[v] = dist[u] + edge[i].d;
if(!vis[v]){
vis[v] = 1;
STACK[top++] = v;
if(++cnt[v] > n + 1) return false;
}
}

}
}
return true;
}

bool bi(int u){
for(int i = 1; i <= n; i++)if(g[u][i]){
int v = i;
if(color[u] == color[v]) return false;
if(!color[v]){
color[v] = 3 - color[u];
if(!bi(v)) return false;
}
}
return true;
}

void solve(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%s", G[i] + 1);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
g[i][j] = G[i][j] - '0';
init();
for(int i = 1; i <= n; i++)if(!color[i]){
color[i] = 1;
if(!bi(i)){
printf("No\n");
return;
}
}
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++)if(i != j){
if(g[i][j]){
if(color[i] == 1) add(i, j, -T);
else add(j, i, -T);
}
else{
if(color[i] == 1) add(j, i, T - 1);
else add(i, j, T - 1);
}
}
for(int i = 1; i <= n; i++){
if(color[i] == 1) add(0, i, T - 1), add(i, 0, 0);
else add(i, 0, T - 1), add(0, i, 0);
}
if(spfa(0)) printf("Yes\n");
else printf("No\n");
}

int main()
{
int T;
scanf("%d", &T);
while(T--) solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: