HDU - 4598 Difference

本文探讨了一种特殊类型的图——difference图的判定算法。通过分析图中各顶点间的数值关系及连接特性,设计了一种染色算法与SPFA算法结合的方法,用于验证图是否满足difference属性。文章详细介绍了算法步骤,并提供了C++实现代码。

题意:

有一个图,给图上每个顶点都赋一个实数Ai。如果存在一个正整数T满足下面两个条件,这个图就是一个"difference"。

  1. |Ai| <= T。

  2. (vi, vj) in E <=> |ai - aj| >= T。

  3. 如果点i,j构成的边在图中存在,则 |Ai - Aj| >= T;否则 |Ai - Aj| < T。("<=>" 代表充要条件)

给出图,问这个图是否是一个"difference"。

思路:

  • 有题意可知,任意两个相邻的点,那么他们的值肯定是一正一负,所以随便任意选一个点,假设他是正的,然后染色,如果不能染成功,那就是no,

  • 如果可以染成功,在看看条件2, 那是一个充要条件,所以如果a b两个点不相邻,要满足 |a - b| < T.

  • 对于 i j, 如果 i j 相邻, 且 i 是正数,满足 ai−aj>=Ta_{i} - a_{j} >= T aiaj>=T 也就是 aj−ai<=−Ta_{j} - a_{i} <= -T ajai<=T

  • 对于 i j, 如果 i j 不相邻, 且 i 是正数, 满足 ai−aj<=T−1 a_{i} - a_{j} <= T-1 aiaj<=T1

  • 有可能图不是全联通的,所以要建一个超级原点 0,

  • 如果 i 是正数,满足 0<=ai−a0<=T−1 0 <= a_{i} - a_{0} <= T - 1 0<=aia0<=T1

  • 如果 i 是负数,满足 0<=a0−ai<=T−1 0 <= a_{0} - a_{i} <= T - 1 0<=a0ai<=T1

知道了所有的式子,对于式子形如 a−b<=T a - b <= Tab<=T 建立一条从 b 到 a 权值为 T 的边

最好跑一遍spfa, 判断是不是又负环,如果有那么就输出来 No, 否则就是 Yes。

#include<bits/stdc++.h>
using namespace std;
const int N = 500;
const int INF = 500;
typedef pair<int,int>P;
vector<P>f[N];

int n,m;
int s[N][N],dis[N],dep[N];
bool vv[N];

bool bfs(int u){
    queue<int>q;
    while(!q.empty()) q.pop();
    q.push(u);
    dis[u] = 1;
    while(!q.empty()){
        u = q.front(); q.pop();
        for (int i = 1; i <= n; ++i){
            if (s[u][i] == 1){
                if (dis[i] == 0) {
                    dis[i] = dis[u] ^ 3;
                    q.push(i);
                }
                if (dis[u] == dis[i]) return 1;
            }
        }
    }
    return 0;
}


bool spfa(int u){
    queue<int>q;
    q.push(u);
    dis[u] = 0;
    vv[u] = 1;

    while(!q.empty()){
        u = q.front(); q.pop();
        vv[u] = 0;
        for (auto it: f[u]){
            int v = it.first, w = it.second;
            if (dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                if (!vv[v]){
                    q.push(v);
                    dep[v]++;
                    vv[v] = 1;
                    if (dep[v] > 300) return 1;
                }
            }
        }
    }
    return 0;
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        memset(dis, 0, sizeof dis);
        memset(dep, 0, sizeof dep);
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                scanf("%1d",&s[i][j]);
        bool vis = 0;
        for (int i = 1; i <= n; ++i){
            if (!dis[i]) vis = vis || bfs(i);
            if (vis) break;
        }
        if (vis){
            puts("No");
            continue;
        } 

        for (int i = 1; i <= n; ++i)
            for (int j = i + 1; j <= n; ++j){
                if (s[i][j] == 1){
                    if (dis[i] == 1){
                        f[i].push_back(P{j, -INF});
                    } else {
                        f[j].push_back(P{i, -INF});
                    }
                } else {
                    if (dis[i] == 1){
                        f[j].push_back(P{i,INF-1});
                    } else {
                        f[i].push_back(P{j,INF-1});
                    }
                }
            }
        for (int i = 1; i<= n; ++i){
            if (dis[i] == 1){
                f[0].push_back(P{i, INF-1});
                f[i].push_back(P{0,0});
            } else {
                f[i].push_back(P{0, INF-1});
                f[0].push_back(P{i, 0});
            }
        }
        vis = 0;
        for (int i = 0; i <= n; ++i){
            dis[i] = INF*1000;
            vv[i] = 0;
        }
             
        if (spfa(0)) puts("No"); else puts("Yes");
        for (int i = 0; i <= n;++i)
            f[i].clear();
    }


    return 0;
}
/*
3 
4 
0011 
0001 
1000 
1100 
4
0101
1010
0101
1010


4 
0111 
1001 
1001 
1110 
3 
000
000 
000
*/
### 关于HDU - 6609 的题目解析 由于当前未提供具体关于 HDU - 6609 题目的详细描述,以下是基于一般算法竞赛题型可能涉及的内容进行推测和解答。 #### 可能的题目背景 假设该题目属于动态规划类问题(类似于多重背包问题),其核心在于优化资源分配或路径选择。此类问题通常会给出一组物品及其属性(如重量、价值等)以及约束条件(如容量限制)。目标是最优地选取某些物品使得满足特定的目标函数[^2]。 #### 动态转移方程设计 如果此题确实是一个变种的背包问题,则可以采用如下状态定义方法: 设 `dp[i][j]` 表示前 i 种物品,在某种条件下达到 j 值时的最大收益或者最小代价。对于每一种新加入考虑范围内的物体 k ,更新规则可能是这样的形式: ```python for i in range(n): for s in range(V, w[k]-1, -1): dp[s] = max(dp[s], dp[s-w[k]] + v[k]) ``` 这里需要注意边界情况处理以及初始化设置合理值来保证计算准确性。 另外还有一种可能性就是它涉及到组合数学方面知识或者是图论最短路等相关知识点。如果是后者的话那么就需要构建相应的邻接表表示图形结构并通过Dijkstra/Bellman-Ford/Floyd-Warshall等经典算法求解两点间距离等问题了[^4]。 最后按照输出格式要求打印结果字符串"Case #X: Y"[^3]。 #### 示例代码片段 下面展示了一个简单的伪代码框架用于解决上述提到类型的DP问题: ```python def solve(): t=int(input()) res=[] cas=1 while(t>0): n,k=list(map(int,input().split())) # Initialize your data structures here ans=find_min_unhappiness() # Implement function find_min_unhappiness() res.append(f'Case #{cas}: {round(ans)}') cas+=1 t-=1 print("\n".join(res)) solve() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值