ZOJ 1638 Greedy Island

还是论文题

话说照我这个速度要刷到猴年马月(他喵的已经是猴年了QAQ)

这题模型挺好想得,很直观的最大费用最大流,唯一要想一下的就是优化了。

当然还有个很坑爹的地方就是spfa可以求2维费用流(两个关键字)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int inf=1e9;
struct Edge{int from,to,next,v,c,c1;}e[200005];
int head[310],cnt;
void ins(int u,int v,int w,int c,int c1){
	e[++cnt]=(Edge){u,v,head[u],w,c,c1};head[u]=cnt;
}
void insert(int u,int v,int w,int c,int c1){
	ins(u,v,w,c,c1);ins(v,u,0,-c,-c1);
}
int d[310],from[310],h[310];
bool inq[310];
bool spfa(int s,int t,int &cost,int &sum){
	memset(d,-0x3f,sizeof(d));
	memset(h,-0x3f,sizeof(h));
	d[s]=0;h[s]=0;queue<int>q;q.push(s);
	while(!q.empty()){
		int u=q.front();q.pop();inq[u]=0;
		for(int i=head[u];i;i=e[i].next)
		if(e[i].v&&(d[e[i].to]<d[u]+e[i].c||(d[e[i].to]==d[u]+e[i].c&&h[e[i].to]<h[u]+e[i].c1))){
			d[e[i].to]=d[u]+e[i].c;
			h[e[i].to]=h[u]+e[i].c1;
			from[e[i].to]=i;
			if(!inq[e[i].to])inq[e[i].to]=1,q.push(e[i].to);
		}
	}
	if(d[t]<0)return false;
	int x=inf;
	for(int i=from[t];i;i=from[e[i].from])x=min(x,e[i].v);
	for(int i=from[t];i;i=from[e[i].from])
	e[i].v-=x,e[i^1].v+=x;
	cost+=x*d[t];sum+=x*h[t];
	return true;
}
int ans,sum;
void mcf(int s,int t){while(spfa(s,t,ans,sum));}
int A,B,C,a[100105],b[100105],c[100105],rk[100105];
bool cmpa(int i,int j){
	if(a[i]==a[j])return a[i]+b[i]+c[i]>a[j]+b[j]+c[j];
	return a[i]>a[j];
}
bool cmpb(int i,int j){
	if(b[i]==b[j])return a[i]+b[i]+c[i]>a[j]+b[j]+c[j];
	return b[i]>b[j];
}
bool cmpc(int i,int j){
	if(c[i]==c[j])return a[i]+b[i]+c[i]>a[j]+b[j]+c[j];
	return c[i]>c[j];
}
int id[310];
int main(){
	//freopen("a.in","r",stdin);
	int cas;scanf("%d",&cas);
	while(cas--){
		int n;scanf("%d",&n);
		scanf("%d%d%d",&A,&B,&C);
		ans=sum=0;
		for(int i=1;i<=n;i++)
		scanf("%d%d%d",&a[i],&b[i],&c[i]);
		
		for(int i=1;i<=n;i++)rk[i]=i;
		sort(rk+1,rk+1+n,cmpa);
		for(int i=1;i<=A+B+C;i++)id[i]=rk[i];
		
		for(int i=1;i<=n;i++)rk[i]=i;
		sort(rk+1,rk+1+n,cmpb);
		for(int i=1;i<=A+B+C;i++)id[i+A+B+C]=rk[i];
		
		for(int i=1;i<=n;i++)rk[i]=i;
		sort(rk+1,rk+1+n,cmpc);
		for(int i=1;i<=A+B+C;i++)id[i+2*(A+B+C)]=rk[i];
		
		int m=3*(A+B+C);
		sort(id+1,id+1+m);m=unique(id+1,id+1+m)-id-1;
		memset(head,0,sizeof(head));cnt=1;
		int S=0,p1=m+1,p2=m+2,p3=m+3,T=m+4;
		insert(S,p1,A,0,0);insert(S,p2,B,0,0);insert(S,p3,C,0,0);
		for(int i=1;i<=m;i++){
			insert(p1,i,1,a[id[i]],a[id[i]]+b[id[i]]+c[id[i]]);
			insert(p2,i,1,b[id[i]],a[id[i]]+b[id[i]]+c[id[i]]);
			insert(p3,i,1,c[id[i]],a[id[i]]+b[id[i]]+c[id[i]]);
			insert(i,T,1,0,0);
		}
		mcf(S,T);
		printf("%d %d\n",ans,sum);
	}
	return 0;
}


你可能感兴趣的:(ZOJ 1638 Greedy Island)