Vijos 1144 小胖守皇宫(https://vijos.org/p/1144)
一棵树上;有边直接相连的点可以互相望见。每个点都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。要在看守全部点的前提下,使得花费的经费最少。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct node
{
long long x,y,next;
//x父亲y儿子
}a[110000];
long long len,last[110000];
long long v[11000],f[11000][5];
bool bk[11000];
void ins(long long x,long long y)
{
len++;
a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;
}
void treedp(int x)
{
f[x][2]=v[x];f[x][0]=0;f[x][1]=0;
/*f[x][2]:自己看自己
f[x][0]:让自己的儿子来看自己
f[x][1]:让自己的父亲来看自己
PS:f数组储存的都是总费用
*/
long long minn=999999999;
bool bkk=false;
for (int k=last[x];k;k=a[k].next)
{//遍历一遍
long long y=a[k].y;
if (bk[y]==false)
{
bk[y]=true;
treedp(y);
minn=min(minn,f[y][2]-f[y][0]);
//寻找代价最小的儿子
//f[y][2]-f[y][0]计算让儿子自己看自己的费用
f[x][0]+=min(f[y][0],f[y][2]);
if (f[y][2]<=f[y][0]) bkk=true;
//如果自己看自己的费用总是小于让儿子来看他的费用,那么标记一下,不用儿子来看他
f[x][1]+=f[y][0];//继承
f[x][2]+=min(f[y][0],min(f[y][1],f[y][2]));//取最小值
}
}
if (bkk==false) f[x][0]+=minn;
//如果没有儿子来看他,那么让代价最小的儿子来看着他
}
int main()
{
long long n;
scanf("%lld",&n);
memset(f,0,sizeof(f));
for (int i=1;i<=n;i++)
{
long long x,k,m,y;
scanf("%lld%lld%lld",&x,&k,&m);
v[x]=k;
for (int j=1;j<=m;j++)
{
scanf("%lld",&y);
ins(x,y);ins(y,x);
}
}
long long root=1;
memset(bk,false,sizeof(bk)); bk[root]=true;
treedp(root);
printf("%lld\n",min(f[root][0],f[root][2]));
return 0;
}
如果不分儿子爸爸的情况:(其实都一样)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
struct node
{
LL x,y,next;
}a[110000];
LL last[110000],len;
LL f[110000][5],s[110000];
bool bk[110000];
void build (LL x,LL y)
{
len++;
a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;
}
/* f[x][0]:不放人,安全
f[x][1]:不放人,不安全
f[x][2]:放人,安全
f[x][3]:放人,不安全(不存在)
*/
void treedp(int x)
{
f[x][2]=s[x];f[x][0]=f[x][1]=0;
LL minn=1<<20;
bool bkk=false;
for (int k=last[x];k;k=a[k].next)
{
LL y=a[k].y;
if (bk[y]==false)
{
bk[y]=true;
treedp(y);
minn=min(f[y][2]-f[y][0],minn);
f[x][0]+=min(f[y][0],f[y][2]);
if (f[y][2]<f[y][0]) bkk=true;
f[x][1]+=f[y][0];
f[x][2]+=min(f[y][0],min(f[y][1],f[y][2]));
}
}
if (!bkk) f[x][0]+=minn;
}
int main()
{
LL n;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
int k,m,x,y;
scanf("%d%d%d",&x,&k,&m);
s[x]=k;
for (int j=1;j<=m;j++)
{
scanf("%d",&y);
build(x,y);build(y,x);
}
}
memset(bk,false,sizeof(bk));
bk[1]=true;
treedp(1);
printf("%d",min(f[1][0],f[1][2]));
return 0;
}