BZOJ2539: [Ctsc2000]丘比特的烦恼
【传送门:BZOJ2539】
简要题意:
给出n个男生的坐标和名字,n个女生的坐标和名字,给出有些男生和女生交往的缘分值,没有给出的男女之间的缘分值为1,要求只有当一对男女之间的连线没有经过任意一个人而且欧几里得距离不超过K的时候,这对男女就可以交往
求出最大的缘分值总和
题解:
首先用字典树存名字,注意输入名字的时候最好全部变成大写或小写
然后用叉积判断是否经过任意一个人,然后建边
发现是带权二分图匹配,好像是KM算法。。听都没听过,更别说会了
将就着用费用流做吧,st连向男生,流量为1,费用为0,每对交往关系连边,流量为1,费用为缘分值,女生连向ed,流量为1,费用为0
然后跑最大费用最大流
坑点:
①名字忽略大小写的区别~读进来以后全都转化成大写或者小写
②没有提到的那些人之间的边都是1!
③不合法的边都要赋值成-inf,不能是0
④判断连线上有没有别的点的时候可以搞个计算几何板子上去然后用叉积,如果不用叉积的话注意判断分母为0的情况
⑤读边的时候男的和女的读进来的顺序是不确定的,要自己判断交换一下= =并不知道有没有男的和女的名字是一样的
⑥数据中会出现重边2333!然而不要取Max,直接无脑覆盖就可以了2333
⑦判断退出的时候不能只判断读入的字符串前三个字符是“End”就退出因为有一组数据里面有一个叫做Enda的人蛤蛤蛤
来自BZOJ评论。。。
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct trie { int c[27],s; trie() { s=0; memset(c,-1,sizeof(c)); } }tr[51000];int tot; char s[21]; void bt(int p) { int x=0,len=strlen(s+1); for(int i=1;i<=len;i++) { if(s[i]>='A'&&s[i]<='Z') s[i]=s[i]-'A'+'a'; int y=s[i]-'a'+1; if(tr[x].c[y]==-1) tr[x].c[y]=++tot; x=tr[x].c[y]; } tr[x].s=p; } struct node { int x,y; }C[61]; char s1[21],s2[21]; struct edge { int x,y,d,c,next,other; }a[110000];int len,last[210]; void ins(int x,int y,int d,int c) { int k1=++len,k2=++len; a[k1].x=x;a[k1].y=y;a[k1].d=d;a[k1].c=c; a[k1].next=last[x];last[x]=k1; a[k2].x=y;a[k2].y=x;a[k2].d=-d;a[k2].c=0; a[k2].next=last[y];last[y]=k2; a[k1].other=k2; a[k2].other=k1; } int d[210],pre[210],pos[210]; bool v[210]; int list[210]; int st,ed; bool spfa() { memset(d,-63,sizeof(d)); d[st]=0; memset(v,false,sizeof(v)); v[st]=true; list[1]=st; int head=1,tail=2; bool bk=false; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0&&d[y]<d[x]+a[k].d) { d[y]=d[x]+a[k].d; pos[y]=x; pre[y]=k; if(v[y]==false) { if(y==ed) bk=true; v[y]=true; list[tail++]=y; } } } head++; v[x]=false; } return bk; } int ans,t; void Flow() { while(spfa()) { t++; ans+=d[ed]; int x; for(x=ed;x!=st;x=pos[x]) { a[pre[x]].c--; a[a[pre[x]].other].c++; } } } int map[61][61]; int dis(node n1,node n2) { return (n1.x-n2.x)*(n1.x-n2.x)+(n1.y-n2.y)*(n1.y-n2.y); } double multi(node p1,node p2,node p0) { double x1,x2,y1,y2; x1=p1.x-p0.x; y1=p1.y-p0.y; x2=p2.x-p0.x; y2=p2.y-p0.y; return x1*y2-x2*y1; } int main() { int K,n; scanf("%d%d",&K,&n); tot=0; for(int i=1;i<=2*n;i++) { scanf("%d%d",&C[i].x,&C[i].y); scanf("%s",s+1); bt(i); } for(int i=1;i<=n;i++) for(int j=n+1;j<=2*n;j++) map[i][j]=map[j][i]=1; while(scanf("%s",s1+1)!=EOF) { if(s1[1]=='E'&&s1[2]=='n'&&s1[3]=='d'&&strlen(s1+1)==3) break; scanf("%s",s2+1); int d;scanf("%d",&d); int x,y,len,t1,t2; x=0;len=strlen(s1+1); for(int i=1;i<=len;i++) { if(s1[i]>='A'&&s1[i]<='Z') s1[i]=s1[i]-'A'+'a'; y=s1[i]-'a'+1; x=tr[x].c[y]; } t1=tr[x].s; x=0;len=strlen(s2+1); for(int i=1;i<=len;i++) { if(s2[i]>='A'&&s2[i]<='Z') s2[i]=s2[i]-'A'+'a'; y=s2[i]-'a'+1; x=tr[x].c[y]; } t2=tr[x].s; map[t1][t2]=map[t2][t1]=d; } st=0,ed=2*n+1; for(int i=1;i<=n;i++) ins(st,i,0,1); for(int i=n+1;i<=2*n;i++) ins(i,ed,0,1); for(int i=1;i<=n;i++) { for(int j=n+1;j<=2*n;j++) { bool bk=true; if(K*K<dis(C[i],C[j])) continue; for(int k=1;k<=2*n;k++) { if(i!=k&&j!=k) { if(multi(C[i],C[k],C[j])==0&&((C[i].x<C[k].x&&C[k].x<C[j].x)||(C[j].x<C[k].x&&C[k].x<C[i].x)||(C[i].y<C[k].y&&C[k].y<C[j].y)||(C[j].y<C[k].y&&C[k].y<C[i].y))) { bk=false;break; } } } if(bk==true) ins(i,j,map[i][j],1); } } Flow(); printf("%d\n",ans); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚