[bzoj 4080] Wf2014 Sensor Network
2015-06-13 07:58
281 查看
will讲的题,网上几乎都是用随机化算法过得,代码短的出奇,为了维护标算的尊严,我决定推广一下表算。。。。
你敢信这题是二分图最大独立集!?
枚举距离不超过d的两个点,已这两个点为圆心,距离为半径分别作圆,会形成如下的图形
可以看到上半部分的点之间距离小于等于d,严格来说是小于确定两点之间的距离。下部分同理。
但是上下部分的点之间距离可能超过d,在这些点对之间连一条边。求最大独立集即为此两点确定的情况下最多可选的点数。
所有点对算出的答案取大值即可。
方案就用网络流,对残余网络搜索,确定两个点集和割边,确定最小点覆盖,取反后即为最大独立集。
不要忘了判断只能选一个点的情况,我wa了一下午。。。。。
代码巨长巨丑,但毕竟是官方解法。。。。
你敢信这题是二分图最大独立集!?
枚举距离不超过d的两个点,已这两个点为圆心,距离为半径分别作圆,会形成如下的图形
可以看到上半部分的点之间距离小于等于d,严格来说是小于确定两点之间的距离。下部分同理。
但是上下部分的点之间距离可能超过d,在这些点对之间连一条边。求最大独立集即为此两点确定的情况下最多可选的点数。
所有点对算出的答案取大值即可。
方案就用网络流,对残余网络搜索,确定两个点集和割边,确定最小点覆盖,取反后即为最大独立集。
不要忘了判断只能选一个点的情况,我wa了一下午。。。。。
代码巨长巨丑,但毕竟是官方解法。。。。
#include <cmath> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int INF = 1e9; int flow[10005]; int vis[105],v[105],mat[105]; int node[10005],next[10005]; int a[105],c[105],cur[105]; int js[105],ex[105],q[105]; int n,d,ans,p1,p2,minx,N,tot,l,r; bool flag; vector <int> e[105], ANS; struct Point { int x,y; void read() { scanf("%d%d",&x,&y); } Point operator -(const Point &a)const { return (Point){x-a.x, y-a.y}; } } dot[105]; int dis(Point P1,Point P2) { return (P1.x-P2.x)*(P1.x-P2.x)+(P1.y-P2.y)*(P1.y-P2.y); } int mult(Point P1,Point P2) { return P1.x*P2.y-P2.x*P1.y; } int mult(Point P0,Point P1,Point P2) { return mult(P1-P0,P2-P0); } bool Judge(int x,int h){ if (vis[x]==h) return 0; vis[x] = h; int len = e[x].size(); for (int i=0;i<len;i++) if (mat[e[x][i]]==0 || Judge(mat[e[x][i]],h)) {mat[e[x][i]] = x; return 1;} return 0; } void calc(int t1,int t2){ int dd = dis(dot[t1],dot[t2]); int tmp = 0; for (int i=1;i<=n;i++) if (i!=t1 && i!=t2 && dis(dot[i],dot[t1])<=dd && dis(dot[i],dot[t2])<=dd) { if (mult(dot[t1],dot[t2],dot[i])>0) v[i] = 1; else v[i] = 2; tmp++; } else v[i] = 0; for (int i=1;i<=n;i++) mat[i] = 0, e[i].clear(); for (int i=1;i<=n;i++) if (v[i]==1) for (int j=1;j<=n;j++) if (v[j]==2) if (dis(dot[i],dot[j])>d*d) e[i].push_back(j); for (int i=1;i<=n;i++) vis[i]=0; for (int i=1;i<=n;i++) if (v[i]==1 && Judge(i,i)) tmp--; if (tmp+2>ans){ ans = tmp+2; p1 = t1; p2 = t2; } } int cnt; void add(int x,int y,int z){ node[++tot]=y; next[tot]=a[x]; a[x]=tot; flow[tot]=z; node[++tot]=x; next[tot]=a[y]; a[y]=tot; flow[tot]=0; } void init(){ memset(c,10,sizeof(c)); memset(js,0,sizeof(js)); for (q[l=r=1]=N,js[c =0]=1;l<=r;l++) for (int i=a[q[l]];i;i=next[i]) if ((i&1) && c[node[i]]>c[q[l]]+1) js[ c[ q[++r]=node[i] ] = c[q[l]]+1 ]++; for (int i=1;i<=N;i++) ex[i] = N-1, cur[i] = a[i]; } void sap(int x){ if (x==N){ flag = 1; cnt-=minx; return; } int minn = minx, i; for (i=cur[x];i;i=next[i]) if (flow[i]){ if (c[x]==c[node[i]]+1){ minx = min(minx, flow[i]); sap(node[i]); if (c[1]>=N) return; if (flag) break; else minx=minn; } ex[x] = min(ex[x], c[node[i]]); } cur[x] = i; if (flag){ flow[i] -= minx; flow[i^1] += minx; cur[node[i]] = max(cur[node[i]], i^1); } else { if (--js[c[x]]==0) c[1] = N; js[ c[x]=ex[x]+1 ]++; cur[x] = a[x]; ex[x] = N-1; for (i=a[x];i;i=next[i]) if (flow[i^1] && c[node[i]]==c[x]+1){ cur[node[i]] = max(cur[node[i]], i^1); ex[node[i]] = min(ex[node[i]], c[x]); } } } void dfs(int x){ if (vis[x]==1) return; vis[x] = 1; for (int i=a[x];i;i=next[i]) if (flow[i]) dfs(node[i]); } void print(){ int dd = dis(dot[p1],dot[p2]); for (int i=1;i<=n;i++) if (i!=p1 && i!=p2 && dis(dot[i],dot[p1])<=dd && dis(dot[i],dot[p2])<=dd) { if (mult(dot[p1],dot[p2],dot[i])>0) v[i] = 1; else v[i] = 2; } else v[i] = 0; N = n+2; tot = 1; for (int i=1;i<=n;i++) if (v[i]==1) add(1,i+1,1); else if (v[i]==2) add(i+1,N,1); for (int i=1;i<=n;i++) if (v[i]==1) for (int j=1;j<=n;j++) if (v[j]==2) if (dis(dot[i],dot[j])>d*d) add(i+1,j+1,INF); init(); while (c[1]<N) {flag=0;minx=INF;sap(1);} for (int i=1;i<=N;i++) vis[i] = 0; dfs(1); ANS.push_back(p1); ANS.push_back(p2); for (int i=2;i<N;i++) if ((v[i-1]==1 && vis[i]==1) || (v[i-1]==2 && vis[i]==0)) ANS.push_back(i-1); while (!ANS.empty()){ printf("%d",ANS.back()); ANS.pop_back(); if (ANS.empty()) printf("\n"); else printf(" "); } } int main(){ scanf("%d%d",&n,&d); for (int i=1;i<=n;i++) dot[i].read(); for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) if (dis(dot[i],dot[j])<=d*d) calc(i,j); if (ans==0){ printf("1\n1\n"); return 0; } printf("%d\n",ans); print(); return 0; }
相关文章推荐
- 获取网络软件更新信息 并发送消息 通知 handler 更新UI
- android 获取 版本号 和 手机的 部分信息
- Docker的安全基准
- Python 学习笔记6
- Oracle数据库之PL/SQL程序基础设计
- 黑马程序员——高新技术-反射
- [问题2015S14] 复旦高等代数 II(14级)每周一题(第十五教学周)
- 实验五
- Redis 集群部署( 转载)
- 06-13最新Xcode7 beta版迅雷离线下载
- 电脑故障:win7键盘失灵,鼠标能用
- HID接收到的数据转成字串 bytes 转成 string
- OSChina 周六乱弹 —— 掉进粪坑是种怎样的体验?
- Android 生成keystore,两种方式(转载)
- 人穷久了或者累久了会sb
- ScaleYViewPager
- Android 生成keystore,两种方式(转载)
- ElasticDownload
- 黑马程序员——java基础——集合框架(二: 双列集合 (Map体系))
- Android 生成keystore,两种方式(转载)