• 图论(KM算法):COGS 290. [CTSC2008] 丘比特的烦恼


    290. [CTSC2008] 丘比特的烦恼

    ★★★   输入文件:cupid.in   输出文件:cupid.out   简单对比
    时间限制:1 s   内存限制:128 MB

      随着社会的不断发展,人与人之间的感情越来越功利化。最近,爱神丘比特发现,爱情也已不再是完全纯洁的了。这使得丘比特很是苦恼,他越来越难找到合适的男女,并向他们射去丘比特之箭。于是丘比特千里迢迢远赴中国,找到了掌管东方人爱情的神——月下老人,向他求教。
    月下老人告诉丘比特,纯洁的爱情并不是不存在,而是他没有找到。在东方,人们讲究的是缘分。月下老人只要做一男一女两个泥人,在他们之间连上一条红线,那 么它们所代表的人就会相爱——无论他们身处何地。而丘比特的爱情之箭只能射中两个距离相当近的人,选择的范围自然就小了很多,不能找到真正的有缘人。
    丘比特听了月下老人的解释,茅塞顿开,回去之后用了人间的最新科技改造了自己的弓箭,使得丘比特之箭的射程大大增加。这样,射中有缘人的机会也增加了不少。
    情人节(Valentine's day)的午夜零时,丘比特开始了自己的工作。他选择了一组数目相等的男女,感应到他们互相之间的缘分大小,并依此射出了神箭,使他们产生爱意。他希望能 选择最好的方法,使被他选择的每一个人被射中一次,且每一对被射中的人之间的缘分的和最大。
    当然,无论丘比特怎么改造自己的弓箭,总还是存在缺陷的。首先,弓箭的射程尽管增大了,但毕竟还是有限的,不能像月下老人那样,做到“千里姻缘一线牵 ”。其次,无论怎么改造,箭的轨迹终归只能是一条直线,也就是说,如果两个人之间的连线段上有别人,那么莫不可向他们射出丘比特之箭,否则,按月下老人的话,就是“乱点鸳鸯谱”了。
    作为一个凡人,你的任务是运用先进的计算机为丘比特找到最佳的方案。

    输入文件格式:
    输入文件第一行为正整数k,表示丘比特之箭的射程,第二行为正整数n(n<30),随后有2n行,表示丘比特选中的人的信息,其中前n行为男子,后n行为女子。每个人的信息由两部分组成:他的姓名和他的位置。姓名是长度小于20且仅包含字母的字符串,忽略大小写的区别, 位置是由一对整数表示的坐标,它们之间用空格分隔。格式为x y Name。输入文件剩下的部分描述了这些人的缘分。每一行的格式为Name1 Name2 p。Name1和Name2为有缘人的姓名,p是他们之间的缘分值(p为小于等于255的正整数)。以一个End作为文件结束标志。每两个人之间的缘分如果被描述多次,以最后一次为准。如果没有被描述,则说明他们缘分值为1。

    输出文件格式:
    输出文件仅一个正整数,表示每一对被射中的人之间的缘分的总和。这个和应当是最大的。

    输入样例
    2
    3
    0 0 Adam
    1 1 Jack
    0 2 George
    1 0 Victoria
    0 1 Susan
    1 2 Cathy
    Adam Cathy 100
    Susan George 20
    George Cathy 40
    Jack Susan 5
    Cathy Jack 30
    Victoria Jack 20
    Adam Victoria 15
    End

    输出样例
    65

      裸题,直接上模板。

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 #include <cmath>
      5 using namespace std;
      6 const int INF=2147483647;
      7 char name[80][30],s1[30],s2[30];
      8 int n,m,k,pos[80][2];
      9 
     10 bool Dist(int n1,int n2){
     11     return sqrt((pos[n1][0]-pos[n2][0])*(pos[n1][0]-pos[n2][0])
     12                +(pos[n1][1]-pos[n2][1])*(pos[n1][1]-pos[n2][1]))<=k;
     13 }
     14 
     15 bool Dir(int n1,int n2){
     16     if(pos[n1][0]==pos[n2][0]){
     17         for(int i=1;i<=n;i++)
     18             if(i!=n1&&i!=n2)
     19                 if(pos[i][0]==pos[n1][0])
     20                     if(pos[i][1]<=max(pos[n1][1],pos[n2][1])
     21                      &&pos[i][1]>=min(pos[n1][1],pos[n2][1]))
     22                         return false;
     23         return true;
     24     }
     25     
     26     for(int i=1;i<=n;i++)
     27         if(i!=n1&&i!=n2)
     28             if(pos[i][0]<=max(pos[n1][0],pos[n2][0])
     29              &&pos[i][0]>=min(pos[n1][0],pos[n2][0]))    
     30             if((pos[n1][1]-pos[i][1])*(pos[n2][0]-pos[i][0])==
     31                (pos[n2][1]-pos[i][1])*(pos[n1][0]-pos[i][0]))
     32             return false;
     33             
     34     return true;        
     35 }
     36 
     37 int w[80][80],lx[80],ly[80],slack[80],sx[80],sy[80],match[80];
     38 
     39 bool Search(int x){
     40     sx[x]=true;
     41     for(int y=1;y<=n;y++){
     42         if(!w[x][y])continue;
     43         int t=lx[x]+ly[y]-w[x][y];
     44         if(t)slack[y]=min(slack[y],t);
     45         else{
     46             if(sy[y])continue;
     47             sy[y]=true;
     48             if(!match[y]||Search(match[y])){
     49                 match[y]=x;
     50                 return true;
     51             }
     52         }
     53     }
     54     return false;    
     55 }
     56 
     57 int KM(){
     58     memset(match,0,sizeof(match));
     59     memset(lx,0x80,sizeof(lx));
     60     memset(ly,0,sizeof(ly));
     61     for(int x=1;x<=n;x++)
     62         for(int y=1;y<=n;y++)
     63             lx[x]=max(lx[x],w[x][y]);
     64                 
     65     for(int x=1;x<=n;x++){
     66         memset(slack,127,sizeof(slack));
     67         while(true){
     68             memset(sx,0,sizeof(sx));
     69             memset(sy,0,sizeof(sy));
     70             if(Search(x))break;
     71             
     72             int minn=INF;
     73             for(int y=1;y<=n;y++)
     74                 if(!sy[y])
     75                     minn=min(slack[y],minn);
     76             
     77             for(int j=1;j<=n;j++)
     78                 if(sx[j])
     79                     lx[j]-=minn;
     80             
     81             for(int y=1;y<=n;y++)
     82                 if(sy[y])
     83                     ly[y]+=minn;
     84                 else
     85                     slack[y]-=minn;                
     86         }
     87     }
     88     int ret=0;
     89     for(int i=1;i<=n;i++)
     90         ret+=w[match[i]][i];
     91     return ret/2;    
     92 }
     93 
     94 int main(){
     95     freopen("cupid.in","r",stdin);
     96     freopen("cupid.out","w",stdout);
     97     scanf("%d%d",&k,&n);n*=2;
     98     for(int i=1;i<=n;i++)
     99         scanf("%d%d %s",&pos[i][0],&pos[i][1],name[i]);
    100     
    101     for(int i=1;i<=n;i++)
    102         for(int j=0;name[i][j];j++)
    103             if(name[i][j]<='Z'&&name[i][j]>='A')
    104                 name[i][j]-='A'-'a';
    105     
    106     while(true){
    107         scanf("%s",s1);
    108         if(!strcmp(s1,"End"))
    109             break;
    110         scanf("%s",s2);    
    111         int n1,n2;
    112         for(n1=0;s1[n1];n1++)
    113             if(s1[n1]<='Z'&&s1[n1]>='A')
    114                 s1[n1]-='A'-'a';
    115         
    116         for(n2=0;s2[n2];n2++)
    117             if(s2[n2]<='Z'&&s2[n2]>='A')
    118                 s2[n2]-='A'-'a';
    119         
    120         for(int i=1;i<=n;i++)
    121             if(!strcmp(s1,name[i])){
    122                 n1=i;
    123                 break;
    124             }
    125         
    126         for(int i=1;i<=n;i++)
    127             if(!strcmp(s2,name[i])){
    128                 n2=i;
    129                 break;
    130             }
    131         int K;scanf("%d",&K);
    132         if(Dist(n1,n2)&&Dir(n1,n2))
    133             w[n2][n1]=w[n1][n2]=K;    
    134     }    
    135     
    136     for(int n1=1;n1<=n;n1++)
    137         for(int n2=1;n2<=n;n2++)
    138             if(n1!=n2&&!w[n1][n2])
    139                 if(Dist(n1,n2)&&Dir(n1,n2))
    140                     w[n1][n2]=w[n2][n1]=1;
    141 
    142     printf("%d
    ",KM());            
    143     return 0;
    144 }
    尽最大的努力,做最好的自己!
  • 相关阅读:
    把程序的定义与实现部分用头文件与源文件分开
    简单控件的应用(二)—学生管理系统
    Java基础14
    创建插入符、输出不同效果的文字
    Java基础12
    简单控件的应用(一)—prj计算器
    简单的Win 32 Application
    最简单的音乐播放器
    消息处理初步
    基于MFC,在非客户区与客户区利用CButon类创建button
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5330607.html
Copyright © 2020-2023  润新知