[HDOJ 4924] Football Manager [枚举+费用流]

69 篇文章 0 订阅
17 篇文章 0 订阅

球队有至多20个人,派11个人出战。每个人出战每个位置会有一定的战斗力,有的人不能出战某些位置,一共有4个位置。某些人和某些人如果同时在场的话会让战斗力上升或下降。现在已知每个位置需要的人数,求最高战斗力。

枚举所有情况,然后费用流判断是否可行,以及最大费用。

每当决定选一个人的时候,就把这个流量流过去,不再选他的时候再把流量退回来。复杂度为C(20,11)*m,m为图中的边数。边数不会超过100条,C(20,11)为1.7*10^5左右..

而且事实证明...因为SPFA的时候记录路径..常数好像比较大..于是差点TLE..压线飘过了...

题解说的不是这样..题解说用dp计算是否可行及最大费用,状态不会超过300多..因为常数比较小..所以比较快..

#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>

using namespace std;

const int MAXINT=(1<<30);
const int N=30;
const int M=200;

struct Node {
	int fe,curCost,fromEdge;
	bool inque;
};
struct Edge {
	int f,t,ne,c;
};
Node a[N];
Edge b[M*2];
int t,nd,p,cost;
void clear(int nn,int tt) {
	nd=nn;t=tt;
	for (int i=0;i<nd;i++) a[i].fe=-1;
	p=0; cost=0;
}
void putedge(int x,int y,int f,int c) {
	//printf("%d %d %d %d\n",x,y,f,c);
	b[p].ne=a[x].fe; b[p].t=y; b[p].f=f; b[p].c=c; a[x].fe=p++;
	b[p].ne=a[y].fe; b[p].t=x; b[p].f=0; b[p].c=-c; a[y].fe=p++;
}
int edg[20][100];
int edgSize[20];
bool spfa(int s) {
	static int d[N];
	int i,p,q,j;
	for (i=0;i<nd;i++) {
		a[i].curCost=-MAXINT;
		a[i].fromEdge=-1;
		a[i].inque=false;
	}
	p=q=0;
	d[q++]=s;
	a[s].inque=true;
	a[s].curCost=0;
	while (p!=q) {
		i=d[p];
		for (j=a[i].fe;j!=-1;j=b[j].ne) {
			Node &tmp=a[b[j].t];
			if (b[j].f>0&&b[j].c+a[i].curCost>tmp.curCost) {
				tmp.curCost=a[i].curCost+b[j].c;
				tmp.fromEdge=j;
				if (tmp.inque==false) {
					tmp.inque=true;
					d[q]=b[j].t;
					q++;
					if (q>N) q-=N;
				}
			}
		}
		a[i].inque=false;
		p++;
		if (p>N) p-=N;
	}
	if (a[t].curCost==-MAXINT) return false;
	for (i=t;i!=s;) {
		int tmp=a[i].fromEdge;
		b[tmp].f--;
		b[tmp^1].f++;
		cost+=b[tmp].c;
		edg[s][edgSize[s]++]=tmp;
		i=b[tmp^1].t;
	}
	return true;
}
void decflow(int i) {
	for (int j=0;j<edgSize[i];j++) {
		int tmp=edg[i][j];
		b[tmp].f++;
		b[tmp^1].f--;
	}
	edgSize[i]=0;
}

int n,ans;
int benefitP[20][40];
int benefitV[20][40];
int benefitSize[20];
bool choose[20];

void readData() {
	static map<int,int> c;
	int i,j,x,y,m;
	char str[10];
	scanf("%d",&n);
	clear(n+5,n+4);
	for (i=0;i<n;i++) {
		choose[i]=false;
		edgSize[i]=0;
		benefitSize[i]=0;
	}
	c.clear();
	for (i=0;i<n;i++) {
		scanf("%d",&x);
		c[x]=i;
		scanf("%d",&m);
		for (j=0;j<m;j++) {
			scanf("%s%d%d",str,&x,&y);
			//printf("%s %d %d\n",str,x,y);
			x=(x+1000)*40000+y+1000;
			if (str[0]=='G') putedge(i,n,1,x);
			else if (str[0]=='D') putedge(i,n+1,1,x);
			else if (str[0]=='M') putedge(i,n+2,1,x);
			else if (str[0]=='S') putedge(i,n+3,1,x);
		}
	}
	scanf("%d",&m);
	for (i=0;i<m;i++) {
		scanf("%d%d%s%d",&x,&y,str,&j);
		//printf("%d %d %s %d\n",x,y,str,j);
		x=c[x];y=c[y];
		if (x<y) swap(x,y);
		if (str[0]=='D') j=-j;
		int &tmp=benefitSize[x];
		benefitP[x][tmp]=y;
		benefitV[x][tmp]=j*40000;
		tmp++;
	}
	scanf("%d-%d-%d",&x,&y,&j);
	//printf("%d %d %d\n",x,y,j);
	putedge(n,t,1,0);
	putedge(n+1,t,x,0);
	putedge(n+2,t,y,0);
	putedge(n+3,t,j,0);
	ans=-MAXINT;
}

void findAns(int i,int res) {
	if (res==0) {
		if (cost>ans) ans=cost;
	} else {
		//for (int j=0;j<n;j++) if (choose[j]) printf("%d ",j);
		//printf("--%d %d %d\n",i,res,n);
		for (;i+res<=n;i++) {
			choose[i]=true;
			int tmp=benefitSize[i];
			int tmpcost=cost;
			for (int j=0;j<tmp;j++) if (choose[benefitP[i][j]]) cost+=benefitV[i][j];
			if (spfa(i))
			   findAns(i+1,res-1);
			decflow(i);
			choose[i]=false;
			cost=tmpcost;
		}
	}
}

int main() {
	int t;
	scanf("%d",&t);
	while (t--) {
		readData();
		findAns(0,11);
		if (ans==-MAXINT) printf("Poor Manager!\n");
		else printf("%d %d\n",ans/40000-11000,ans%40000-11000);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值