您的位置:首页 > 其它

[bzoj 4080] Wf2014 Sensor Network

2015-06-13 07:58 281 查看
will讲的题,网上几乎都是用随机化算法过得,代码短的出奇,为了维护标算的尊严,我决定推广一下表算。。。。

你敢信这题是二分图最大独立集!?

枚举距离不超过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;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: