prow2012-A3-0014
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
题意:有N组,每组有2个球心坐标,要从每组中选一个球心,使得选取的球之间两两不相交的半径最大。
较裸的2-sat判定问题,二分了某个半径R后,可以根据是否会冲突决定建图,比如a组的0会碰到b组的1,那么建边就是a_0-->b_0
在建出的图上求强联通分量,如果a_0,a_1在同一强联通分量内,即false.
{{{
#include <iostream>
#include <vector>
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
struct edges {
int node, next;
} edge[400000], edge2[400000];
int node[1000], node2[1000], num, num2, belong[1000],Q[10000];
int N;
double D[500][2][3];
void add(int a, int b, edges *tmpedge, int *tmpnode, int &num) {
tmpedge[num].node = b;
tmpedge[num].next = tmpnode[a];
tmpnode[a] = num++;
}
bool mark[1000];
int T[10000];
int Knum, Tnum;
void dfs1(int now) { //?????DFS
mark[now] = true;
for (int i = node[now]; i != -1; i = edge[i].next)
if (!mark[edge[i].node]) dfs1(edge[i].node);
T[Tnum++] = now;
}
void dfs2(int now) { //????????DFS
belong[now] = Knum;
mark[now] = true;
for (int i = node2[now]; i != -1; i = edge2[i].next)
if (!mark[edge2[i].node]) dfs2(edge2[i].node);
return;
}
double sqr(double x){
return x*x;
}
double eps = 1e-6;
double calcD(int i,int k1,int j,int k2){
double ans = 0;
for (int t=0;t<3;t++)
ans+=sqr(D[i][k1][t]-D[j][k2][t]);
return sqrt(ans);
}
bool check(double mid){
int i,j,k1,k2;
num = num2 = 0;
memset(node, -1, sizeof (node));
memset(node2, -1, sizeof (node2));
for (i=0;i<N;i++)
for (j=0;j<N;j++)
if (i!=j){
for (k1 = 0;k1<2;k1++)
for (k2=0;k2<2;k2++){
if (calcD(i,k1,j,k2)<mid*2){
add(i*2+k1, j*2+1-k2, edge, node, num);
add(j*2+1-k2, i*2+k1, edge2, node2, num2);
}
}
}
Tnum = Knum = 0;
memset(mark, false, sizeof (mark));
for (i = 0; i < 2 * N; i++)
if (!mark[i])
dfs1(i);
memset(mark, false, sizeof (mark));
for (i = Tnum - 1; i >= 0; i--) { //???????DFS
if (!mark[T[i]])
{
Q[Knum] = T[i]; //????????????????
dfs2(T[i]), Knum++;
}
}
for (i=0;i<2*N;i+=2)
if (belong[i]==belong[i+1])
{
return false;
}
return true;
}
int main() {
int a, b, i, j, k;
while(scanf("%d",&N)!=EOF){
for (i=0;i<N;i++){
for (k=0;k<2;k++)
for (j=0;j<3;j++)
scanf("%lf",&D[i][k][j]);
}
double L = 0,R = 1000000,mid,ans = 0;
int tim = 50;
while(tim--&&L<R){
mid = (L+R)/2;
if (check(mid)) ans = mid,L = mid+eps;
else R = mid-eps;
}
printf("%.3lf\n",ans);
}
}
}}}
题意:有N组,每组有2个球心坐标,要从每组中选一个球心,使得选取的球之间两两不相交的半径最大。
较裸的2-sat判定问题,二分了某个半径R后,可以根据是否会冲突决定建图,比如a组的0会碰到b组的1,那么建边就是a_0-->b_0
在建出的图上求强联通分量,如果a_0,a_1在同一强联通分量内,即false.
#include <iostream>
#include <vector>
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
struct edges {
int node, next;
} edge[400000], edge2[400000];
int node[1000], node2[1000], num, num2, belong[1000],Q[10000];
int N;
double D[500][2][3];
void add(int a, int b, edges *tmpedge, int *tmpnode, int &num) {
tmpedge[num].node = b;
tmpedge[num].next = tmpnode[a];
tmpnode[a] = num++;
}
bool mark[1000];
int T[10000];
int Knum, Tnum;
void dfs1(int now) { //?????DFS
mark[now] = true;
for (int i = node[now]; i != -1; i = edge[i].next)
if (!mark[edge[i].node]) dfs1(edge[i].node);
T[Tnum++] = now;
}
void dfs2(int now) { //????????DFS
belong[now] = Knum;
mark[now] = true;
for (int i = node2[now]; i != -1; i = edge2[i].next)
if (!mark[edge2[i].node]) dfs2(edge2[i].node);
return;
}
double sqr(double x){
return x*x;
}
double eps = 1e-6;
double calcD(int i,int k1,int j,int k2){
double ans = 0;
for (int t=0;t<3;t++)
ans+=sqr(D[i][k1][t]-D[j][k2][t]);
return sqrt(ans);
}
bool check(double mid){
int i,j,k1,k2;
num = num2 = 0;
memset(node, -1, sizeof (node));
memset(node2, -1, sizeof (node2));
for (i=0;i<N;i++)
for (j=0;j<N;j++)
if (i!=j){
for (k1 = 0;k1<2;k1++)
for (k2=0;k2<2;k2++){
if (calcD(i,k1,j,k2)<mid*2){
add(i*2+k1, j*2+1-k2, edge, node, num);
add(j*2+1-k2, i*2+k1, edge2, node2, num2);
}
}
}
Tnum = Knum = 0;
memset(mark, false, sizeof (mark));
for (i = 0; i < 2 * N; i++)
if (!mark[i])
dfs1(i);
memset(mark, false, sizeof (mark));
for (i = Tnum - 1; i >= 0; i--) { //???????DFS
if (!mark[T[i]])
{
Q[Knum] = T[i]; //????????????????
dfs2(T[i]), Knum++;
}
}
for (i=0;i<2*N;i+=2)
if (belong[i]==belong[i+1])
{
return false;
}
return true;
}
int main() {
int a, b, i, j, k;
while(scanf("%d",&N)!=EOF){
for (i=0;i<N;i++){
for (k=0;k<2;k++)
for (j=0;j<3;j++)
scanf("%lf",&D[i][k][j]);
}
double L = 0,R = 1000000,mid,ans = 0;
int tim = 50;
while(tim--&&L<R){
mid = (L+R)/2;
if (check(mid)) ans = mid,L = mid+eps;
else R = mid-eps;
}
printf("%.3lf\n",ans);
}
}