题解:P4209 学习小组
wangxx2012 · · 题解
被题目吓哭了...
题意
给定
建图
先别看那个恶心人的
我们建一个超级源点
接着对于第
最后,就是连学生
Q:为什么是要连学生到汇点?
A:因为学生有可能选小组,也可能不选。
那有人就说了,学生
当然不对!
回归题目,题目在要求求出最小支出前,还要求参与学生尽量多。
这该怎么解决?
当然是强迫参加咯!
什么意思?即我们将学生
解决完以上问题,我们就该考虑那个恶心人的
我们很容易想到一个式子:
我们受到启发,从小组
建图毕。
代码
按上述方法建图,再跑一遍最小费用最大流即可。 :::success[Code]
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int maxn=1e5+10;
const int inf=1e8;
int n,m,k,s,t;
int f[maxn];
char ch[110][110];
struct node{
int to,next,cap,cost;
}e[2*maxn];
int head[maxn],tot=1;
void add(int u,int v,int cap,int cost){
e[++tot].to=v;
e[tot].cap=cap; e[tot].cost=cost;
e[tot].next=head[u];
head[u]=tot;
}
int dis[maxn],cur[maxn];
bool st[maxn],vis[maxn];
bool spfa(){
queue<int> q;
fill(st+1,st+2*n+m+2,0);
fill(dis+1,dis+2*n+m+2,inf);
q.push(s); dis[s]=0; st[s]=1;
while(!q.empty()){
int u=q.front(); q.pop();
st[u]=0;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(dis[v]>dis[u]+e[i].cost&&e[i].cap){
dis[v]=dis[u]+e[i].cost;
if(!st[v]){
q.push(v);
st[v]=1;
}
}
}
}
return dis[t]!=inf;
}
int dfs(int u,int flow,int &mincost){
if(u==t) return flow;
int used=flow;
vis[u]=1;
for(int i=cur[u];i;i=e[i].next){
cur[u]=i;
int v=e[i].to;
if(dis[v]==dis[u]+e[i].cost&&e[i].cap&&!vis[v]){
int rlow=dfs(v,min(used,e[i].cap),mincost);
e[i].cap-=rlow; e[i^1].cap+=rlow;
used-=rlow; mincost+=rlow*e[i].cost;
if(used==0) break;
}
}
vis[u]=0;
return flow-used;
}
int dinic(int &mincost){
int ans=0;
while(spfa()){
memcpy(cur,head,sizeof(head));
ans+=dfs(s,inf,mincost);
}
return ans;
}
int edge[maxn];
int dfs1(){
int cnt=0;
for(int i=1;i<=n;i++){
if(!e[edge[i]].cap) cnt++;
}
return cnt;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>m>>k; s=0,t=n+m+1;
for(int i=1;i<=n;i++) add(s,i,k,0),add(i,s,0,0);
for(int i=1;i<=m;i++){
int c;
cin>>c;
for(int j=1;j<=n;j++){
int w=c*(2*j-1);
add(n+i,t,1,w); add(t,n+i,0,-w);
}
}
for(int i=1;i<=m;i++) cin>>f[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char ch;
cin>>ch;
if(ch=='0') continue;
add(i,n+j,1,-f[j]); add(n+j,i,0,f[j]);
}
}
for(int i=1;i<=n;i++) add(i,t,k-1,0),add(t,i,0,0);
int mincost=0; dinic(mincost);
cout<<mincost;
return 0;
}
:::