标签:
题意: 给一个图,问能否给每个点分配一个实数值,使得存在一个数实数T,所有点满足:|value(i)| < T 且 u,v之间有边<=> |value(u)-value(v)| >= T。(注意等价符号)
思路:
由性质可得,两相邻点的分配的值的符号相反,于是先对原图做一个二分图判定,如果是非二分图,则无解。对二分图染色后,假设color[i]=1,则表示i点为正值,color[i]=-1,则表示为负。在已知每个点正负值的基础上,绝对值符号可以去掉,差分约束模型便出来了。这里有个细节,由于是实数,在遇到<和<=的时候比较麻烦,幸运的是我们可以用整数来代替实数,比如条件a < b可以看成是 a <= (b - 1),只要整数范围足够大即可。
这样,问题看上去解决了,但是我后来想了一下,用color值来决定正负是存在问题的,color值只能将一个连通分量内的点值分成两个集合,也就是说color值只能作为一种区分标记,并不能直接决定哪一个集合为正,哪一个集合为负。但是我在网上看了很多题解,都没有考虑这个问题就直接用color值往下做了,却也能够过,于是我猜想可以任意指定一个为正,另一个为负。尝试性的证明了一下:
假设原图确实存在一组合法解,其中某一个连通分量记为S,S内的点的点值从小到大排序后如下(出现的字母都为非负数):
{-a, -b, ..., c, d},(a > b, c < d) -------(1)
其余点的点值从小到大排序后如下:
{-u, -v, ..., x, y}, (u > v, x < y}
两个点值集合所对应的点的集合之间是没有边相连的,由于已将点值排序,所以有:
a+y < T, u+d < T。
重新给S内点分配点值如下:
{d, d - (a - b), ..., -a + (d - c), -a} -------(2)
(1)和(2)对应位置的值属于相同的点,比如-a和d是同一个点的点值,我们不难发现,重新分配后,所有S内点的点值都变了符号(也就是把二分图的正负集合交换了一下,如果能够证明交换后仍有解,则足以说明猜想成立),且重新分配后的点值不相邻的边的绝对值之差依然满足小于T(因为最大绝对值之差还是a+y或u+d,它们都是小于T的),对于连通分量内部,由于上述分配并没有改变相邻点之间的差,所以任意两点之差也就没改变,所以绝对值之差不会变!
也就是说,如果有解,那么任意指定二分图的一个集合为正,解都可以被找到。证毕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <cmath> #include <algorithm> using namespace std; const int T = 12345; struct Graph { vector<vector< int > > G; void clear() { G.clear(); } void resize( int n) { G.resize(n + 2); } void add( int u, int v) { G[u].push_back(v); } vector< int > & operator [] ( int u) { return G[u]; } }; Graph G, E; int n; bool mark[345][345]; int vis[345]; void add( int u, int v, int w) { G.add(v, u); E.add(v, w); } queue< int > Q; int D[345], cnt[345]; bool relax( int u, int v, int w) { if (D[u] > D[v] + w) { D[u] = D[v] + w; return true ; } return false ; } bool SPFA( int s) { while (!Q.empty()) Q.pop(); memset (D, 0x3f, sizeof (D)); memset (cnt, 0, sizeof (cnt)); D[s] = 0; memset (vis, 0, sizeof (vis)); vis[s] = 1; cnt[s] ++; Q.push(s); while (!Q.empty()) { int node = Q.front(); Q.pop(); vis[node] = 0; int sz = G[node].size(); for ( int i = 0; i < sz; i ++) { int u = G[node][i]; if (relax(u, node, E[node][i])) { if (!vis[u]) { vis[u] = 1; cnt[u] ++; if (cnt[u] > n) return false ; Q.push(u); } } } } return true ; } bool Color( int k, int c) { vis[k] = c; for ( int i = 0; i < n; i ++) { if (mark[k][i]) { if (vis[i]) { if (vis[i] == vis[k]) return false ; } else if (!Color(i, -c)) return false ; } } return true ; } bool check() { memset (vis, 0, sizeof (vis)); for ( int i = 0; i < n; i ++) { if (!vis[i]) { if (!Color(i, 1)) return false ; } } G.clear(); E.clear(); G.resize(n); E.resize(n); // 添加一个源点编号为 n, 并从源点引出n条到每个点的有向边,边权为0 for ( int i = 0; i < n; i ++) { add(i, n, 0); } for ( int i = 0; i < n; i ++) { for ( int j = i + 1; j < n; j ++) { if (mark[i][j]) { if (vis[i] > 0) add(j, i, -T); else add(i, j, -T); } else { if (vis[i] > 0) add(i, j, T - 1); else add(j, i, T - 1); } } } n ++; // 多了一个源点 return SPFA(n - 1); } int main() { #ifndef ONLINE_JUDGE freopen ( "in.txt" , "r" , stdin); #endif // ONLINE_JUDGE int T; cin >> T; while (T --) { cin >> n; memset (mark, 0, sizeof (mark)); for ( int i = 0; i < n; i ++) { char s[345]; scanf ( "%s" , s); for ( int j = 0; j < n; j ++) { mark[i][j] = s[j] == ‘1‘ ; } } puts (check()? "Yes" : "No" ); } return 0; } |
标签:
原文地址:http://www.cnblogs.com/jklongint/p/4553596.html