zoukankan      html  css  js  c++  java
  • COJ 3007 Mr.Yang的小助手

    传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1037

    试题描述:

    信息学社团已经逐渐发展壮大,成员也越来越多。现在,有n个同学有了关于信息学的问题,公务繁忙的杨老师决定派出n个小助手来帮助他们解答问题。现在问题来了,每个小助手和它对应的同学不能离的太远(要不然杨老师会觉得场面很乱…),也就是说两个人的距离不能超过杨老师的规定值Distance。同时,俩个人的中间不能隔有其他同学(要不然同学们会互相干扰的…),就是说在两个同学a,b所连成的线段上不能有同学c。现在,每解答一个问题(我们认为小助手足够聪明,只要有匹配的人都可以解答他们的问题),杨老师都会奖励小助手一些积分,现在,贪心的小助手们联合起来想让他们获取的积分总数尽量大…请你帮小助手们编写一个程序来算出他们能获得的最大的积分数。(一些题目补充见“其他说明”)

    输入:

    第一行是一个正整数Distance表示杨老师规定的最大范围。
    第二行是一个正整数n,表示有n个同学。
    接下来的n行是每个同学的x,y坐标及他们的名字。再接下来的n行是每个小助手的x,y坐标及他们的名字。
    输入文件剩下的部分描述了一些同学与特定小助手解答完问题能获得的杨老师的奖励。每一行的格式为Name1 Name2 p。Name1和Name2为同学,小助手的姓名,p是他们之间的可以获得的积分。以一个End作为文件结束标志。每两个人之间的奖励积分如果被描述多次,则以最后一次的描述为准。如果没有被描述,则说明他们奖励积分为1。

    输出:

    一个正整数w,表示小助手们能获得的最多的积分数。 

    输入示例:

    2 3
    0 0 zYT
    1 1 WJh
    0 2 XYz
    1 0 XJR
    0 1 WZJ
    1 2 LZJ
    ZYt LZJ 100
    WZJ XYZ 20
    XYZ LZJ 40
    WJH WzJ 5
    WJH LZJ 30
    XJR WJH 20
    ZYT XJR 15
    End

    输出示例:

    65

    其他说明:

    一些小问题:
    首先:我们假设同学和小助手都不会移动……
    其次:我们假设杨老师手中有无限积分……
    然后:每个人的名字由于OI出现问题导致大小写随机了,你的程序需要能够正确识别纠错。(具体请看样例)
    再然后:人们的姓名是长度小于200且仅包含字母的字符串(不是汉字)。
    再再然后:保证给出的奖励分数合法,即小助手和小助手不会给出奖励值,同学和同学不会给出奖励值。
    再再再然后:一个小助手只能帮助一个同学,一个同学只能被一个小助手帮助。
    再再再再然后:最后的结果保证在int范围内。
    最后声明:由于数据给的很小,时间卡紧了一点。

    数据范围:
    1 <= n < 30
    1 <= Distance < 10^6
    1 <= x,y < 10^6
    1 <= p <= 1500
    以上所有变量均属于整数集。

    题解:

    【裸体二分图最佳完美匹配】小助手和同学形成了天然的二分图。用向量判重线、预处理两点间距离平方判距离来连边。

    KM的:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <cstring>
      5 using namespace std;
      6 
      7 void read(int& x)
      8 {
      9     x = 0;
     10     int sig = 1;
     11     char ch = getchar();
     12     
     13     while(!isdigit(ch))
     14     {
     15         if(ch == '-') sig = -1;
     16         ch = getchar();
     17     }
     18     
     19     while(isdigit(ch))
     20     {
     21         x = 10 * x + ch - '0';
     22         ch = getchar();
     23     }
     24     
     25     x *= sig;
     26     return ;
     27 }
     28 
     29 const int MAXN = 60 + 5;
     30 const int MAXBIGN = 40 + 5;
     31 const int MAXL = 200 + 10;
     32 const int INF = -1u >> 1;
     33 
     34 struct Person
     35 {
     36     double x, y;
     37     char Name[MAXL];
     38 }P[MAXN];
     39 
     40 int N, M, T;
     41 
     42 double Distance;
     43 
     44 int adj[MAXN][MAXN], Match[MAXN], L[MAXN];
     45 int slack[MAXN];
     46 
     47 bool vis[MAXN];
     48 
     49 double Dist(Person a, Person b)
     50 {
     51     return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
     52 }
     53 
     54 bool Is_Cross(Person a, Person b, Person c)
     55 {
     56     if((a.x - b.x) * (b.y - c.y) == (b.x - c.x) * (a.y - b.y))
     57     {
     58         if(a.y == c.y) return (a.x < b.x && b.x < c.x) || (c.x < b.x && b.x < a.x);
     59         else return (a.y < b.y && b.y < c.y) || (c.y < b.y && b.y < a.y);
     60     }
     61     
     62     return false;
     63 }
     64 
     65 void Try_Shot()
     66 {
     67     for(int i = 1; i <= N; i++)
     68     {
     69           for(int j = M; j <= T; j++)
     70           {
     71                if(Dist(P[i], P[j]) > Distance) adj[i][j] = 0;
     72             else 
     73             {
     74                 int k;
     75                 for(k = 1; k <= T; k++)
     76                     if(k != i && k != j && Is_Cross(P[i], P[k], P[j])) break;
     77                   
     78                    if(k > T) adj[i][j] = 1;
     79                    else adj[i][j] = 0;
     80               }
     81         }
     82     }
     83     
     84     return ;
     85 }
     86 
     87 int Scanname(char *S)
     88 {
     89     for(int i = 1; i <= T; i++)
     90       if(strcmp(P[i].Name, S) == 0) return i;
     91       
     92     return -1;
     93 }
     94 
     95 void Format(char *S)
     96 {
     97     for(; *S; S++) 
     98       if(*S >= 'a' && *S <= 'z') *S = *S - 'a' + 'A';
     99     
    100     return ;
    101 }
    102 
    103 void KM_Init()
    104 {
    105     int p1, p2;
    106     int v;
    107     
    108     char Name[MAXL];
    109     
    110     scanf("%lf", &Distance);
    111     Distance = Distance * Distance;
    112     
    113     read(N);
    114     
    115     M = N + 1;
    116     T = N + N;
    117     
    118     for(int i = 1; i <= T; i++)
    119     {
    120         scanf("%lf%lf", &P[i].x, &P[i].y);
    121         
    122         scanf("%s", P[i].Name);
    123         Format(P[i].Name);
    124     }
    125     
    126     Try_Shot();
    127     
    128     while(scanf("%s", Name) != EOF)
    129     {
    130         if(strcmp(Name, "End") == 0) break;
    131         Format(Name);
    132         p1 = Scanname(Name);
    133         
    134         scanf("%s", Name);
    135         Format(Name);
    136         p2 = Scanname(Name);
    137         
    138         read(v);
    139         
    140         if(p1 > p2) swap(p1, p2);
    141         
    142         if(adj[p1][p2] != 0) adj[p1][p2] = v;
    143     }
    144     
    145     return ;
    146 }
    147 
    148 bool Path(int i)
    149 {
    150     
    151     vis[i] = true;
    152     
    153     for(int j = M; j <= T; j++)
    154     {
    155         if(!vis[j] && adj[i][j] > 0)
    156         {
    157             int t = L[i] + L[j] - adj[i][j];
    158             if(t == 0)
    159             {
    160                 vis[j] = true;
    161                 if(Match[j] == 0 || Path(Match[j]))
    162                 {
    163                     Match[j] = i;
    164                     return true;
    165                 }
    166             }
    167             else slack[j] = min(slack[j], t);
    168         }
    169     }
    170     
    171     return false;
    172 }
    173 
    174 void KM_Solve()
    175 {
    176     int delta;
    177     
    178     for(int i = 1; i <= N; i++)
    179       for(int j = M; j <= T; j++)
    180         L[i] = max(L[i], adj[i][j]);
    181         
    182     for(int i = 1; i <= N; i++)
    183     {
    184         while(1)
    185         {
    186             memset(vis, 0, sizeof(vis));
    187             for(int j = M; j <= T; j++) slack[j] = INF;
    188             if(Path(i)) break;
    189             
    190             delta = INF;
    191             
    192             for(int k = M; k <= T; k++)
    193               if(!vis[k] && slack[k] < delta)
    194                 delta = slack[k];
    195             
    196             for(int j = 1; j <= N; j++)
    197               if(vis[j]) L[j] -= delta;
    198               
    199             for(int j = M; j <= T; j++)
    200               if(vis[j]) L[j] += delta;
    201         }
    202     }
    203 }
    204 
    205 void Print()
    206 {
    207     int Ans = 0;
    208     for(int i = M; i <= T; i++)
    209       Ans += adj[Match[i]][i];
    210     
    211     printf("%d
    ", Ans);
    212     
    213     return ;
    214 }
    215 
    216 int main()
    217 {
    218     KM_Init();
    219     KM_Solve();
    220     Print();
    221     
    222     return 0;
    223 }

    费用流的:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cctype>
      4 #include<queue>
      5 #include<map>
      6 #include<cstring>
      7 #include<algorithm>
      8 #define dist(i,j) (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])
      9 using namespace std;
     10 const int INF=2000000000;
     11 const int maxn=110;
     12 const int maxm=80010;
     13 struct Edge
     14 {
     15     int from,to,cap,flow,cost;
     16 };
     17 struct MCMF
     18 {
     19     int n,m;
     20     int first[maxn],next[maxm];
     21     Edge edges[maxm];
     22     int d[maxn],p[maxn],a[maxn],inq[maxn];
     23     void init(int n)
     24     {
     25         this->n=n;
     26         m=0;
     27         memset(first,-1,sizeof(first));
     28     }
     29     void AddEdge(int from,int to,int cap,int cost)
     30     {
     31         edges[m]=(Edge){from,to,cap,0,cost};
     32         next[m]=first[from];
     33         first[from]=m++;
     34         edges[m]=(Edge){to,from,0,0,-cost};
     35         next[m]=first[to];
     36         first[to]=m++;
     37     }
     38     int BellmanFord(int s,int t,int& flow,int& cost)
     39     {
     40         queue<int> Q;
     41         memset(inq,0,sizeof(inq));
     42         for(int i=1;i<=n;i++) d[i]=INF;
     43         inq[s]=1; d[s]=0; a[s]=INF; Q.push(s);
     44         while(!Q.empty())
     45         {
     46             int x=Q.front(); Q.pop();
     47             inq[x]=0;
     48             for(int i=first[x];i!=-1;i=next[i])
     49             {
     50                 Edge& e=edges[i];
     51                 if(e.cap>e.flow&&d[e.to]>d[x]+e.cost)
     52                 {
     53                     d[e.to]=d[x]+e.cost;
     54                     a[e.to]=min(a[x],e.cap-e.flow);
     55                     p[e.to]=i;
     56                     if(!inq[e.to])
     57                     {
     58                         inq[e.to]=1;
     59                         Q.push(e.to);
     60                     }
     61                 }
     62             }
     63         }
     64         if(d[t]==INF) return 0;
     65         flow+=a[t]; cost+=a[t]*d[t];
     66         int x=t;
     67         while(x!=s)
     68         {
     69             edges[p[x]].flow+=a[t];
     70             edges[p[x]^1].flow-=a[t];
     71             x=edges[p[x]].from;
     72         }
     73         return 1;
     74     }
     75     int solve(int s,int t)
     76     {
     77         int flow=0,cost=0;
     78         while(BellmanFord(s,t,flow,cost));
     79         return cost;
     80     }
     81 }sol;
     82 double maxdist,x[maxn],y[maxn];
     83 map<string,int> S;
     84 int n,m,tot;
     85 int id(string a)
     86 {
     87     int len=a.length();
     88     for(int i=0;i<len;i++) a[i]=tolower(a[i]);
     89     if(!S.count(a))
     90     {
     91         S[a]=++tot;
     92         return tot;
     93     }
     94     return S[a];
     95 }
     96 int can(int a,int c)
     97 {
     98     if((x[a]-x[c])*(x[a]-x[c])+(y[a]-y[c])*(y[a]-y[c])>maxdist*maxdist) return 0;
     99     for(int i=1;i<=n*2;i++) if(i!=a&&i!=c)
    100     {
    101         if((x[i]-x[a])*(x[i]-x[c])>0) continue;
    102         if((y[i]-y[a])*(y[i]-y[c])>0) continue;
    103         if((x[i]-x[a])*(y[c]-y[i])==(y[i]-y[a])*(x[c]-x[i])) return 0;
    104     }
    105     return 1;
    106 }
    107 int w[maxn][maxn];
    108 int main()
    109 {
    110     scanf("%lf%d",&maxdist,&n);
    111     sol.init(n*2+2);
    112     double t1,t2;
    113     for(int i=1;i<=n;i++)
    114        for(int j=n+1;j<=n*2;j++) w[i][j]=1;
    115     for(int i=1;i<=n;i++) 
    116     {
    117         string a;
    118         scanf("%lf%lf",&t1,&t2);cin>>a;
    119         int c=id(a);
    120         x[i]=t1+50;y[i]=t2+50;
    121         sol.AddEdge(n*2+1,i,1,0);
    122     }
    123     for(int i=1;i<=n;i++) 
    124     {
    125         string a;
    126         scanf("%lf%lf",&t1,&t2);cin>>a;
    127         int c=id(a);
    128         x[i+n]=t1+50;y[i+n]=t2+50;
    129         sol.AddEdge(i+n,2*n+2,1,0);
    130     }
    131     while(1)
    132     {
    133         string name;
    134         cin>>name; if(name=="End") break;
    135         int a,b,c;
    136         a=id(name);
    137         cin>>name;
    138         b=id(name);
    139         scanf("%d",&c);
    140         if(a>b) swap(a,b);
    141         w[a][b]=c;
    142     }
    143     for(int i=1;i<=n;i++) 
    144        for(int j=n+1;j<=n*2;j++) if(can(i,j))
    145         sol.AddEdge(i,j,1,-w[i][j]);
    146     printf("%d
    ",-sol.solve(2*n+1,2*n+2));
    147     return 0;
    148 }
  • 相关阅读:
    Go语言基础--1.1 变量的声明
    基本语法
    弹性盒子修改
    弹性盒子内容
    弹性盒子
    响应式列重置
    栅格系统
    布局容器
    额外按钮
    可消失的弹出框
  • 原文地址:https://www.cnblogs.com/chxer/p/4388389.html
Copyright © 2011-2022 走看看