CodeChef DEC14 Course Selection 最小割,建圖,割邊
阿新 • • 發佈:2018-11-04
題意: n門課程,m個學期. 同一門課可能在多個學期中都有開設
a[i][j]表示在第j個學期修第i門課的成績. a[i][j]=-1表示第j個學期沒有開設第i門課.
k個修課條件(u,v) 表示要修第v門課 必須先修完第u門課.
n,m,k,a[i][j]<=100. 問修完n門課的最多平均分為多少?
分母n為固定的,總得分越大,平均分也越大. 反著考慮,總的扣分儘量小(從最小割角度考慮),令a[i][j]= 100 - a[i][j].
建圖:s向(i,1)連線容量為a[i][1]的邊, 對j=[1:m-1] :(i,j)向(i,j+1)連線一條容量為 a[i][j]的邊. (i,m)向匯點連線容量為inf的邊.
此時的最小割就是不考慮k個條件時的最小總扣分 (s->i->t 的路徑上正好一條邊被割去,否則存在路徑).
若有修課條件(u,v) 意味著u的割邊必須要在v的割邊之前.
s向(v,1)連線容量為inf的邊.(u,j)向(v,j+1)連線一條容量為inf的邊.
這樣建圖u的割邊一定在v的割邊之前.【若u割邊在v之後,則s->u->v->t存在路徑】
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> ii; const int N=2e2+5,M=6e4+5,inf=0x3f3f3f3f; int n,m,k,a[N][N],head[N*N],tot,s,t,dis[N*N]; void init(){ tot=0; memset(head,-1,sizeof(head)); s=0,t=n*m+1; } struct edge{ int to,nxt,cap; edge(){} edge(int to,int nxt,int cap):to(to),nxt(nxt),cap(cap){} }e[M]; void add_edge(int u,int v,int cap){ e[tot]=edge(v,head[u],cap); head[u]=tot++; e[tot]=edge(u,head[v],0); head[v]=tot++; } bool bfs(){ queue<int> q; memset(dis,-1,sizeof(dis)); q.push(s),dis[s]=0; while(!q.empty()){ int u=q.front();q.pop(); for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(dis[v]==-1&&e[i].cap>0) dis[v]=dis[u]+1,q.push(v); } } return dis[t]!=-1; } int dfs(int u,int x){ if(u==t||x==0) return x; int res=0; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(dis[v]!=dis[u]+1) continue; int dx=dfs(v,min(e[i].cap,x)); if(dx>0){ e[i].cap-=dx,e[i^1].cap+=dx; x-=dx,res+=dx; if(x==0) return res; } } dis[u]=-1; return res; } int Dinic(){ int res=0; while(bfs()) res+=dfs(s,inf); return res; } int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>n>>m>>k; init(); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>a[i][j]; if(a[i][j]==-1) a[i][j]=inf; else a[i][j]=100-a[i][j]; if(j==1) add_edge(s,(i-1)*m+j,a[i][j]); else add_edge((i-1)*m+j-1,(i-1)*m+j,a[i][j]); } add_edge((i-1)*m+m,t,inf); } for(int p=0;p<k;p++){ int u,v; cin>>u>>v; for(int j=1;j<=m;j++){ if(j==1) add_edge(s,(v-1)*m+j,inf); else add_edge((u-1)*m+j-1,(v-1)*m+j,inf); } } double res=100*n-Dinic(); cout<<fixed<<setprecision(2)<<res/(1.0*n)<<'\n'; return 0; }