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\n", 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\n",-sol.solve(2*n+1,2*n+2)); 147 return 0; 148 }