HDU 4598 Difference 差分约束 + 判奇圈

本文探讨了一种特殊的无向图问题,通过构建差分约束系统并利用SPFA算法来判断图是否存在特定条件下的解。文章详细介绍了建图过程及二分染色法的应用,并给出了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给你一个无向图 这个图是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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值