3 4 5 6 6 8 10 12 14 16 7 7 6 7 3 5 3 4 5 6 6 8 10 12 14 16 5 5 5 5 5 5 0
7 33.333% Oh, I lose my dear seaco!
二分图的最优匹配。图很容易建立。再处理相似度的时候。把每个权值扩大100倍。然后再对i==j时 特殊标记。使他们的权值再++1。后面选择的时候就很容易挑出。按原匹配
匹配的个数。 100*(double)(res%100)/n。即可得到第二问。
#include <cstring> #include <cstdio> #include <queue> #include <iostream> #define inf 0x3f3f3f3f #define MAXN 3000 #define MAXM 30000 using namespace std; struct node { int u,v,f,c; }; node e[MAXM]; int first[MAXN],next[MAXM],cc; int inq[MAXN],pre[MAXN],preedge[MAXN],d[MAXN]; inline void add_edge(int u,int v,int f,int c) { e[cc].u=u; e[cc].v=v; e[cc].f=f; e[cc].c=c; next[cc]=first[u]; first[u]=cc; cc++; e[cc].v=u; e[cc].u=v; e[cc].f=0; e[cc].c=-c; next[cc]=first[v]; first[v]=cc; cc++; } int SPFA(int s,int t) { memset(inq,0,sizeof(inq)); int i; for(i=0;i<=t;i++) d[i]=-inf; memset(pre,-1,sizeof(pre)); memset(preedge,-1,sizeof(preedge)); d[s]=0; queue<int> q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; int i; for(i=first[u];i!=-1;i=next[i]) { int v=e[i].v; if(e[i].f) { if(d[v]<d[u]+e[i].c) { d[v]=d[u]+e[i].c; pre[v]=u; preedge[v]=i; if(!inq[v]) { inq[v]=1; q.push(v); } } } } } if(d[t]==-inf) return 0; else return 1; } int Min_Cost_Flow(int s,int t) { int ans_flow=0,ans_cost=0,mm,tmp; while(SPFA(s,t)) { mm=inf; int u=t; while(pre[u]!=-1) { tmp=preedge[u]; mm=min(mm,e[tmp].f); u=pre[u]; } u=t; while(pre[u]!=-1) { tmp=preedge[u]; e[tmp].f-=mm; e[tmp^1].f+=mm; u=pre[u]; } ans_flow+=mm; ans_cost+=mm*d[t]; } return ans_cost; } int V[100],H[100],P[100],A[100],B[100]; int win(int i,int j) { int x,y; if(P[j]%A[i]==0) x=P[j]/A[i]; else x=P[j]/A[i]+1; if(H[i]%B[j]==0) y=H[i]/B[j]; else y=H[i]/B[j]+1; if(x<=y) return 1; else return 0; } int main() { int n; while(scanf("%d",&n),n) { memset(first,-1,sizeof(first)); memset(next,-1,sizeof(next)); cc=0; int i; for(i=1;i<=n;i++) scanf("%d",&V[i]); for(i=1;i<=n;i++) scanf("%d",&H[i]); for(i=1;i<=n;i++) scanf("%d",&P[i]); for(i=1;i<=n;i++) scanf("%d",&A[i]); for(i=1;i<=n;i++) scanf("%d",&B[i]); int s=0,t=2*n+1,j; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if(win(i,j)) { if(i==j) add_edge(i,n+j,1,V[i]*100+1); else add_edge(i,n+j,1,V[i]*100); } else { if(i==j) add_edge(i,n+j,1,-V[i]*100+1); else add_edge(i,n+j,1,-V[i]*100); } } } for(i=1;i<=n;i++) { add_edge(0,i,1,0); add_edge(n+i,t,1,0); } int res=Min_Cost_Flow(s,t); if(res/100<=0) printf("Oh, I lose my dear seaco!\n"); else printf("%d %.3f%%\n",res/100,100*1.0*(res%100)/n); } return 0; }试了试也可以搞成二维的:
#include <cstring> #include <cstdio> #include <queue> #include <iostream> #define inf 0x3f3f3f3f #define MAXN 3000 #define MAXM 30000 using namespace std; struct node { int u,v,f,c; int c1; }; node e[MAXM]; int first[MAXN],next[MAXM],cc,ss; int inq[MAXN],pre[MAXN],preedge[MAXN],d[MAXN],d1[MAXN]; inline void add_edge(int u,int v,int f,int c,int c1) { e[cc].u=u; e[cc].v=v; e[cc].f=f; e[cc].c=c; e[cc].c1=c1; next[cc]=first[u]; first[u]=cc; cc++; e[cc].v=u; e[cc].u=v; e[cc].f=0; e[cc].c=-c; e[cc].c1=-c1; next[cc]=first[v]; first[v]=cc; cc++; } int SPFA(int s,int t) { memset(inq,0,sizeof(inq)); int i; for(i=0;i<=t;i++) d1[i]=d[i]=-inf; memset(pre,-1,sizeof(pre)); memset(preedge,-1,sizeof(preedge)); d[s]=0; d1[s]=0; queue<int> q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; int i; for(i=first[u];i!=-1;i=next[i]) { int v=e[i].v; if(e[i].f) { if(d[v]<d[u]+e[i].c||(d[v]==d[u]+e[i].c&&d1[v]<d1[u]+e[i].c1)) { d[v]=d[u]+e[i].c; d1[v]=d1[u]+e[i].c1; pre[v]=u; preedge[v]=i; if(!inq[v]) { inq[v]=1; q.push(v); } } } } } if(d[t]==-inf) return 0; else return 1; } int Min_Cost_Flow(int s,int t) { int ans_flow=0,ans_cost=0,mm,tmp; ss=00; while(SPFA(s,t)) { mm=inf; int u=t; while(pre[u]!=-1) { tmp=preedge[u]; mm=min(mm,e[tmp].f); u=pre[u]; } u=t; while(pre[u]!=-1) { tmp=preedge[u]; e[tmp].f-=mm; e[tmp^1].f+=mm; u=pre[u]; } ans_flow+=mm; ans_cost+=mm*d[t]; ss+=d1[t]; } return ans_cost; } int V[100],H[100],P[100],A[100],B[100]; int win(int i,int j) { int x,y; if(P[j]%A[i]==0) x=P[j]/A[i]; else x=P[j]/A[i]+1; if(H[i]%B[j]==0) y=H[i]/B[j]; else y=H[i]/B[j]+1; if(x<=y) return 1; else return 0; } int main() { int n; while(scanf("%d",&n),n) { memset(first,-1,sizeof(first)); memset(next,-1,sizeof(next)); cc=0; int i; for(i=1;i<=n;i++) scanf("%d",&V[i]); for(i=1;i<=n;i++) scanf("%d",&H[i]); for(i=1;i<=n;i++) scanf("%d",&P[i]); for(i=1;i<=n;i++) scanf("%d",&A[i]); for(i=1;i<=n;i++) scanf("%d",&B[i]); int s=0,t=2*n+1,j; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if(win(i,j)) { if(i==j) add_edge(i,n+j,1,V[i],1); else add_edge(i,n+j,1,V[i],0); } else { if(i==j) add_edge(i,n+j,1,-V[i],1); else add_edge(i,n+j,1,-V[i],0); } } } for(i=1;i<=n;i++) { add_edge(0,i,1,0,0); add_edge(n+i,t,1,0,0); } int res=Min_Cost_Flow(s,t); if(res<=0) printf("Oh, I lose my dear seaco!\n"); else printf("%d %.3f%%\n",res,100*1.0*(ss)/n); } return 0; }