版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/87969257
题意:
太鬼扯了自己去看
分析:
很暴力的贪心+网络流check
这种多点共同选择的问题一定要联想到网络流
第一问每次在残留网络上跑看能不能跑出新流量,能跑出即为当前层数。
第二问用二分,每次重建图跑就好了,不用非要去存图,太耗内存而且代码复杂度也差不多。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 510
#define INF 0x3FFFFFFF
using namespace std;
vector<int> a[MAXN],w[MAXN],rev[MAXN];
int s,t,tot;
void add_edge(int u,int v,int val){
a[u].push_back(v);
a[v].push_back(u);
w[u].push_back(val);
w[v].push_back(0);
rev[u].push_back(a[v].size()-1);
rev[v].push_back(a[u].size()-1);
}
int T,C,n,m;
int b[MAXN],S[MAXN],ans[MAXN];
vector<int> tar[MAXN][MAXN];
void build_edge(int x,int y){
for(int i=0;i<int(tar[x][y].size());i++)
add_edge(x,tar[x][y][i]+n,1);
}
void dele_edge(int x,int y){
for(int i=0;i<int(tar[x][y].size());i++){
a[tar[x][y][i]+n].pop_back();
w[tar[x][y][i]+n].pop_back();
rev[tar[x][y][i]+n].pop_back();
}
int sd=int(tar[x][y].size());
for(int i=1;i<=sd;i++)
a[x].pop_back(),w[x].pop_back(),rev[x].pop_back();
}
void clear_it(int x,int i){
w[x][i]=w[a[x][i]][rev[x][i]]+w[x][i];
w[a[x][i]][rev[x][i]]=0;
}
void clear_edge(){
for(int i=0;i<tot;i++)
for(int j=0;j<int(a[i].size());j++)
if(a[i][j]>i)
clear_it(i,j);
}
int d[MAXN],g[MAXN];
int dfs(int x,int f){
if(x==t)
return f;
int less=f;
for(int i=0;i<int(a[x].size())&&less;i++)
if(w[x][i]&&d[a[x][i]]==d[x]-1){
int res=dfs(a[x][i],min(less,w[x][i]));
less-=res;
w[x][i]-=res;
w[a[x][i]][rev[x][i]]+=res;
if(d[s]>tot)
return f-less;
}
if(less==0)
return f;
g[d[x]]--;
if(g[d[x]]==0){
d[s]=tot+1;
return f-less;
}
d[x]=tot+1;
for(int i=0;i<int(a[x].size());i++)
if(w[x][i])
d[x]=min(d[x],d[a[x][i]]);
d[x]++;
g[d[x]]++;
return f-less;
}
int maxf(){
g[0]=tot;
memset(d,0,sizeof d);
int res=0;
while(d[s]<=tot)
res+=dfs(s,INF);
// clear_edge();
return res;
}
bool check(int x,int len){
int sum=1;
clear_edge();
for(int i=1;i<len;i++) {build_edge(i,ans[i]);sum+=(ans[i]!=(m+1));}
for(int i=1;i<=S[x];i++) build_edge(x,i);
int res=maxf();
for(int i=S[x];i>=1;i--) dele_edge(x,i);
for(int i=len-1;i>=1;i--) dele_edge(i,ans[i]);
return res==sum;
}
int b_search(int x){
if(ans[x]<=S[x])
return 0;
int l=1,r=x-1,res=x;
while(l<=r){
int mid=(l+r)>>1;
if(check(x,mid)){
res=x-mid;
l=mid+1;
}
else
r=mid-1;
}
return res;
}
void Print_edges(){
PF("-------------\nPrint edges:\n");
for(int i=0;i<tot;i++){
PF("%d:\n",i);
for(int j=0;j<int(a[i].size());j++)
PF("{%d %d}",a[i][j],w[i][j]);
PF("\n");
}
PF("Print finished!\n---------------\n");
}
int main(){
SF("%d%d",&T,&C);
int x;
while(T--){
SF("%d%d",&n,&m);
s=0;
t=n+m+1;
tot=t+1;
for(int i=1;i<=m;i++){
SF("%d",&b[i]);
add_edge(i+n,t,b[i]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m+1;j++)
tar[i][j].clear();
for(int j=1;j<=m;j++){
SF("%d",&x);
if(x) tar[i][x].push_back(j);
}
}
for(int i=1;i<=n;i++){
SF("%d",&S[i]);
ans[i]=m+1;
add_edge(s,i,1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
build_edge(i,j);
if(maxf()==1){
ans[i]=j;
break;
}
dele_edge(i,j);
}
}
for(int i=1;i<=n;i++)
PF("%d ",ans[i]);
PF("\n");
for(int i=n;i>=1;i--)
dele_edge(i,ans[i]);
for(int i=1;i<=n;i++)
PF("%d ",b_search(i));
PF("\n");
for(int i=0;i<tot;i++)
a[i].clear(),w[i].clear(),rev[i].clear();
}
}