spoj spoj839 Optimal Marks 网络流 最小割 附数据生成器

来源:互联网 发布:认知心理学 知乎 编辑:程序博客网 时间:2024/05/01 10:12

题目大意:


给定一张图,每个点有一个数字,有的点没有数字。


给所有点涂上数字,使得任意直接相连的2个点的数字,xor值的和最小。



对于xor运算,每一位之间没有关系。所以题目首先拆分成31个小问题。。求最后每个数字的每一位(二进制位)的数字。


然后目前的问题就是,一张图,很多点数字是0,很多点数字是1,还有一些点没有上数字。 找一个方案,使得任何直接相连的点的数字,xor值的和最小。


显然0附近的点都写0比较好,1附近的点都写1比较好。 最后1和0交汇了,希望交汇的点尽量小。 这显然就是一个最小割。


然后新原连1的边,0连新汇,流量都是无穷大。


其他原来图中相连的边,都是正反连上流量为1的边即可。


跑一个最大流,割的位置,就是01交汇的地方。


然后从S出发经过的所有点,都涂上1. 其他点都是0.


然后这题就做完了。。


写完程序过了样例交一发WA了。。就去写对拍器。。结果发现数组没清0,导致多组数据WA……忧伤


数据生成器代码

#include <cstdio>#include <cstring>#include <vector>#include <ctime>#include <iostream>#include <cstdlib>using namespace std;char get_rand(){int flag= rand()%3;if (flag==0){return rand()%10 + '0';}if (flag==1){return rand()%26+'a';}return rand()%26+'A';}int rand_from_to(int a, int b){return rand()%(b-a+1) + a;}int f[550][550];typedef pair<int,int>pii;#define mp(a,b) make_pair(a,b)int main(){srand(time(0));int T=2;cout<<T<<endl;while (T--){memset(f,0,sizeof(f));int n =  5;//n个点,m个边int totm = 15;int sb=rand()%totm+1;for (int i = 1; i <= sb;++i){int a = rand()%n+1;int b = rand()%n+1;if (a>b)swap(a,b);f[a][b] = rand()*rand()%10000000+1;}vector<pii>g;for (int i = 1; i <=n;++i)for (int j = i+1; j <=n;++j){if (i==j)continue;if (f[i][j]){g.push_back(mp(i,j));f[j][i]=0;}}cout<<n<<" ";cout<<g.size()<<endl;for (auto x : g){cout<<x.first<<" "<<x.second<<endl;//<<" "<<f[x.first][x.second]<<endl;}g.clear();for (int i = 1; i <= n ; ++ i){int flag = rand()%2;if (flag)continue;g.push_back(mp(i, rand()%10));}cout<<g.size()<<endl;for (auto x : g){cout<<x.first<<" "<<x.second<<endl;//<<" "<<f[x.first][x.second]<<endl;}}return 0;}

ac code

#include <bits/stdc++.h>#include <ext/pb_ds/priority_queue.hpp>#include <tr1/unordered_map>using std::tr1::unordered_map;//using std::setiosflags;//using std::setprecision;using std::sort;using std::max;using std::min;using std::cout;using std::stack;using std::cin;using std::endl;using std::swap;using std::pair;using std::vector;using std::set;using std::map;using std::make_pair;using std::multiset;using std::unique;using std::queue;using std::greater;using std::string;using std::priority_queue;using std::lower_bound;//返回第一个不小于using std::upper_bound;//返回第一个大于using std::max_element;using std::min_element;using __gnu_pbds::pairing_heap_tag;#define x first#define y second#define Hash unordered_map#define clr(x,b) memset((x),(b),sizeof(x))typedef unsigned long long uLL;typedef long long LL;typedef pair<int, int> pii;typedef pair<double, double> pdd;typedef __gnu_pbds::priority_queue<pii, greater<pii>, pairing_heap_tag> Heap;//小根堆typedef Heap::point_iterator Hit;const Hit null;const double PI = acos(-1);const LL LINF = 0x3f3f3f3f3f3f3f3fll;//4e18const int INF = 0x3f3f3f3f;//1e9const double eps = 1e-8;const int MOD = 1 << 16;#define prln(x) cout<<#x<<" = "<<x<<endl#define pr(x) cout<<#x<<" = "<<x<<" "//调用方法://init(n) 初始化 n 为节点数//clear_flow() 清空所有边的流量//add_edge(from, to, cap) 添加边from -> to 容量为cap//maxflow(s, t) 返回s->t的最大流//void mincut(vector<int>& ans) // 调用完maxflow后才可以用,ans里面存最小割//print() 打印整张图,调试用const int maxn = 600;struct Edge { int from, to, cap, flow; };struct ISAP {int n, m, s, t;vector<Edge> edges;vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号bool vis[maxn];        // BFS使用int d[maxn];           // 从起点到i的距离int cur[maxn];        // 当前弧指针int p[maxn];          // 可增广路上的上一条弧int num[maxn];        // 距离标号计数void add_edge(int from, int to, int cap) {edges.push_back((Edge){from, to, cap, 0});edges.push_back((Edge){to, from, 0, 0});m = edges.size();G[from].push_back(m-2);G[to].push_back(m-1);}bool bfs() {memset(vis, 0, sizeof(vis));queue<int> q;q.push(t);vis[t] = 1;d[t] = 0;while(!q.empty()) {int x = q.front(); q.pop();for(int i = 0; i < G[x].size(); i++) {Edge& e = edges[G[x][i]^1];if(!vis[e.from] && e.cap > e.flow) {vis[e.from] = 1;d[e.from] = d[x] + 1;q.push(e.from);}}}return vis[s];}void doit(int ans[]){clr(vis, 0);queue<int>q;q.push(s);vis[s] = 1;d[s] = 0;while (!q.empty()){int x = q.front();ans[x]+=1;q.pop();for (int i = 0; i < G[x].size(); i ++ ){Edge& e = edges[G[x][i]];if (!vis[e.to] && e.cap > e.flow){vis[e.to] = 1;q.push(e.to);}}}}void init(int n) {this->n = n;for(int i = 0; i < n; i++) G[i].clear();edges.clear();}void clear_flow() {for(int i = 0; i < edges.size(); i++) edges[i].flow = 0;    }int augment() {int x = t, a = INF;while(x != s) {Edge& e = edges[p[x]];a = min(a, e.cap-e.flow);x = edges[p[x]].from;}x = t;while(x != s) {edges[p[x]].flow += a;edges[p[x]^1].flow -= a;x = edges[p[x]].from;}return a;}int maxflow(int s, int t) {//到的最大流大于need就停止,如果没有限制,删去含有need的地方this->s = s; this->t = t;int flow = 0;bfs();memset(num, 0, sizeof(num));for(int i = 0; i < n; i++) num[d[i]]++;int x = s;memset(cur, 0, sizeof(cur));while(d[s] < n) {if(x == t) {flow += augment();x = s;}int ok = 0;for(int i = cur[x]; i < G[x].size(); i++) {Edge& e = edges[G[x][i]];if(e.cap > e.flow && d[x] == d[e.to] + 1) { // Advanceok = 1;p[e.to] = G[x][i];cur[x] = i; // 注意x = e.to;break;}}if(!ok) { // Retreatint m = n-1; // 初值注意for(int i = 0; i < G[x].size(); i++) {Edge& e = edges[G[x][i]];if(e.cap > e.flow) m = min(m, d[e.to]);}if(--num[d[x]] == 0) break;//gap优化num[d[x] = m+1]++;cur[x] = 0; // 注意if(x != s) x = edges[p[x]].from;}}return flow;}void mincut(vector<int>& ans) { // 调用完maxflow后才可以用,ans里面存最小割bfs();for(int i = 0; i < edges.size(); i++) {Edge& e = edges[i];if(!vis[e.from] && vis[e.to] && e.cap > 0) ans.push_back(i);}}void print() {printf("Graph:\n");for(int i = 0; i < edges.size(); i++)printf("%d->%d, %d, %d\n", edges[i].from, edges[i].to , edges[i].cap, edges[i].flow);}} isap;int n, m;struct xxx{int u,v;}eee[3000*2];int known_num;int isbiao[600];//是否初始有标号int biao[600];//如果被标了,标的是什么int marks[600];int ans[600];int mp[600][600];void init(){scanf("%d%d", &n, &m);clr(mp,0);for (int i = 0; i != m; ++ i){scanf("%d%d", &eee[i].u, &eee[i].v);mp[eee[i].u][eee[i].v]=1;mp[eee[i].v][eee[i].u]=1;}scanf("%d", &known_num);clr(isbiao, 0);clr(ans, 0);for (int i = 1; i <= known_num; ++ i){int a,b;scanf("%d%d", &a, &b);isbiao[a]=1;biao[a]=b;}}void cal(){isap.init(n + 5);for (int i = 0; i <=n; ++ i)for (int j = i+1; j <=n;++j){if (mp[i][j]){isap.add_edge(i, j, 1);isap.add_edge(j, i, 1);}}for (int i = 1; i <= n; ++ i){if (!isbiao[i])continue;if (marks[i]){isap.add_edge(0, i, INF);}else{isap.add_edge(i, n + 1, INF);}}isap.maxflow(0, n + 1);}void doit(){clr(ans, 0);//初始化标号为0for (int i = 1; i <= 31; ++ i){for (int j = 1; j <= n; ++ j){ans[j]<<=1;if (!isbiao[j])continue;marks[j] = (biao[j]>>(31-i))&1;}cal();isap.doit(ans);}for (int i = 1; i <= n; ++ i)printf("%d\n", ans[i]);}int main(){int T;scanf("%d", &T);while (T--){init();doit();}return 0;}


0 0
原创粉丝点击