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