题目链接:HDU3315
【题意】就是两排怪物的最大权匹配,战斗胜利权值为正,否则为负,如果有多种相同的匹配权值,要让i和i配对的对数尽量多。
【分析】很容易想到是二分图最大权匹配。但是关键在于怎么处理让i和i配对尽量多,其实只要让每个权值放大n倍,然后对i-i边权值在加1,最后求出的权值/n(如果是i-i配对需要-1再/n),至于为什么需要放大n倍是因为如果直接让i-i权值+1会影响最终匹配的结果,放大n倍后即使所有i-i都配对也只多了n,不会影响最终结果。
【AC CODE】46ms
#include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <map> //#include <unordered_map> #include <queue> #include <stack> #include <vector> #include <string> #include <algorithm> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) const int INF = 0x3f3f3f3f, MAXN = 100+10; int g[MAXN][MAXN];//二分图描述,纵坐标为左边,横坐标为右边,这里下标从1开始的 struct KM{ struct NODE{ int to,w; NODE(int a, int b){ to = a, w = b; } }; int nx,ny;//两边的点数 int linker[MAXN],lx[MAXN],ly[MAXN];//y中各点匹配状态,x,y中的点标号 int slack[MAXN]; bool visx[MAXN],visy[MAXN]; bool dfs(int x) { visx[x] = true; repe(y,1,ny) { if(visy[y]) continue; int tmp = lx[x]+ly[y]-g[x][y]; if(!tmp) { visy[y] = true; if(-1 == linker[y] || dfs(linker[y])) { linker[y] = x; return true; } } else if(slack[y] > tmp) slack[y] = tmp; } return false; } int max_km(int nx, int ny)//传入两边点数 { this->nx = nx, this->ny = ny; clc(linker,-1); clc(ly,0); repe(i,1,nx) { lx[i] = -INF; repe(j,1,ny) if(g[i][j] > lx[i]) lx[i] = g[i][j]; } repe(x,1,nx) { clc(slack,0x3f); while(1) { clc(visx,0); clc(visy,0); if(dfs(x))break; int d = INF; repe(i,1,ny) { if(!visy[i] && d > slack[i]) d = slack[i]; } repe(i,1,nx) if(visx[i]) lx[i] -= d; repe(i,1,ny) { if(visy[i]) ly[i] += d; else slack[i] -= d; } } } //最后统计最大值,加负号就是最小值,然后要把所有g[][]*-1 int ans = 0; repe(i,1,ny) { //如果求最小值就是-INF,最大值才是INF //if(INF == g[linker[i]][i]) return -INF;//不存在完美匹配 if(linker[i] == i) ans += (g[linker[i]][i]-1)/nx; else ans += g[linker[i]][i]/nx; } return ans; } }km; int v[MAXN], h[MAXN], p[MAXN], a[MAXN], b[MAXN]; inline int get_cost(int x, int y) { if(p[y]/a[x]+(bool)(p[y]%a[x]) <= h[x]/b[y]+(bool)(h[x]%b[y])) return v[x]; return -v[x]; } int main() { #ifdef SHY freopen("e:\\1.txt", "r", stdin); #endif int n; while(~scanf("%d%*c", &n) && n) { repe(i,1,n) scanf("%d%*c", &v[i]); repe(i,1,n) scanf("%d%*c", &h[i]); repe(i,1,n) scanf("%d%*c", &p[i]); repe(i,1,n) scanf("%d%*c", &a[i]); repe(i,1,n) scanf("%d%*c", &b[i]); repe(i,1,n) { repe(j,1,n) { g[i][j] = get_cost(i,j)*n; if(i == j) g[i][j]++; } } int ans = km.max_km(n,n); if(ans > 0) { printf("%d ", ans); int sum = 0; repe(i,1,n) if(km.linker[i] == i) sum++; printf("%.3lf%%\n", sum*1.0/n*100.0); } else puts("Oh, I lose my dear seaco!"); } return 0; }