CodeChef DEC14 Course Selection 最小割,建图,割边

题意: 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;
}

猜你喜欢

转载自blog.csdn.net/noone0/article/details/83351524