积蓄程度
给定一颗树形的网络 叶子结点为汇点 根节点为源点 求最大流量
换根dp: 适用于对于每一个点都要作为根进行一遍dp的题目
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define pa pair<int,int>
#define mp make_pair
#define fs first
#define sc second
#define F(j,k) f[(j)][(k)+400]
#define G(j,k) g[(j)][(k)+400]
using namespace std;
const int N=205;
const int M=25;
int read()
{
int x=0,f=0,c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return f?-x:x;
}
int h[N],num,a[N],b[N];
int n,m,test,T;
int f[M][805];
pa g[M][805];
void print(int x,int y,pa p)
{
if(!x) return;
print(x-1,p.fs,G(p.fs,p.sc));
if(p.fs==y-1) h[++num]=x;
}
int main()
{
while( (n=read())&&(m=read()))
{
memset(f,0xcf,sizeof f);
f[0][0]=0;num=0; T=0;
for(int i=1;i<=n;i++)
{
int x=read(),y=read();
a[i]=x+y; b[i]=x-y;
}
for(int i=1;i<=n;i++)
for(int j=min(i,m);j>=0;j--)
for(int k=-400;k<=400;k++)
{
G(j,k)=mp(j,k);
if(k-b[i]>=-400&&F(j,k)<F(j-1,k-b[i])+a[i])
F(j,k)=F(j-1,k-b[i])+a[i],G(j,k)=mp(j-1,k-b[i]);
}
int ret=0,tmp=0; pa ans;
for(int i=-400;i<=400;i++)
if(F(m,i)>ret)
{
ret=F(m,i);
ans=G(m,i); tmp=i;
}
printf("Jury #%d\n",++test);
print(n,tmp,ans);
int ans1=0,ans2=0;
for(int i=1;i<=num;i++) ans1+=(a[i]+b[i])/2,ans2+=(a[i]-b[i])/2;
printf("Best jury has value %d for prosecution and value %d for defence:\n",ans1,ans2);
for(int i=1;i<=num;i++) printf("%d ",h[i]);
puts("");
}
return 0;
}
值得注意的点在于源点的度数可能为1 需要加以特判
在添加特判条件的时候 要注意与其他条件的关系
注意考虑谁先判断 谁后判断

浙公网安备 33010602011771号