题意:给定一个有n(n <= 10000) 个节点的无根树.有两种装置A和B,每种都有无线多个.
在某个节点x使用A装置需要C1(C1 <= 1000)的花费,并且此时与节点x相连的边都被覆盖.
在某个节点X使用B装置需要C2(C2 <= 1000)的费用,并且此时与节点x相连的边以及与节点x相连的点相连的边都被覆盖.
求覆盖所有边的最小花费.
分析:状态有很多种表示方法,f[u][a][b][c] 表示第i个点选了a装置,他父亲选了b装置,c表示它的儿子中是否有选C2装置,或者f[u][a][b][c]表示第i个点选了a装置,他父亲选了b装置,c表示u到fa[u]的边是否被u上边的点覆盖,这两种状态定义方法都能转移,其实这道题的状态表示方法不难想到,难就在这个状态猛一看很多,给人一种无从下手的感觉,其实手动列一下这18个状态就会发现它们的转移其实一共就三种类型.
第二种状态表示方法:
#include <bits/stdc++.h>
#define N 10005
#define INF 1047483647
#define MOD 1000000007
using namespace std;
int n,u,v,c1,c2,f[N][3][3][2],dp[N][2];
vector<int> G[N];
void dfs(int u,int fa)
{
for(int v : G[u])
if(v != fa) dfs(v,u);
for(int i = 0;i < 3;i++)
for(int j = 0;j < 3;j++)
for(int k = 0;k < 2;k++)
{
if(!k && j) continue;
f[u][i][j][k] = !i ? 0:(i == 1 ? c1 : c2);
int t = 0,V_tot = 0;
dp[0][1] = INF;
for(int v : G[u])
if(v != fa)
{
t++;
V_tot += min(min(f[v][0][i][i || (j==2)],f[v][1][i][i || (j==2)]),f[v][2][i][i || (j==2)]);
dp[t][0] = dp[t-1][0] + min(f[v][0][i][1],f[v][1][i][1]);
dp[t][1] = min(dp[t-1][1] + min(f[v][2][i][1],min(f[v][0][i][1],f[v][1][i][1])),dp[t-1][0] + f[v][2][i][0]);
}
if(!(i+j+k)) f[u][i][j][k] += dp[t][1];
else
if(!i && j < 2) f[u][i][j][k] += min(dp[t][1],V_tot);
else f[u][i][j][k] += V_tot;
}
}
int main()
{
while(~scanf("%d%d%d",&n,&c1,&c2) && (n+c1+c2))
{
for(int i = 1;i <= n;i++) G[i].clear();
for(int i = 1;i < n;i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
cout<<min(min(f[1][0][0][1],f[1][1][0][1]),f[1][2][0][1])<<endl;
}
}
第一种状态表示方法:
#include <bits/stdc++.h>
#define N 10005
#define INF 1047483647
#define MOD 1000000007
using namespace std;
int n,u,v,c1,c2,f[N][3][3][2],dp[N][2];
vector<int> G[N];
void dfs(int u,int fa)
{
for(int v : G[u])
if(v != fa) dfs(v,u);
for(int i = 0;i < 3;i++)
for(int j = 0;j < 3;j++)
for(int k = 0;k < 2;k++)
{
f[u][i][j][k] = !i ? 0:(i == 1 ? c1 : c2);
int t = 0;
dp[0][1] = INF;
for(int v : G[u])
if(v != fa)
{
t++;
dp[t][0] = dp[t-1][0] + min(min(f[v][0][i][1],f[v][0][i][0]),min(f[v][1][i][1],f[v][1][i][0]));
dp[t][1] = min(dp[t-1][1] + min(min(f[v][2][i][1],f[v][2][i][0]),min(min(f[v][0][i][1],f[v][0][i][0]),min(f[v][1][i][1],f[v][1][i][0]))),dp[t-1][0] + min(f[v][2][i][1],f[v][2][i][0]));
}
if(k == 1) f[u][i][j][k] += dp[t][1];
else
if(!(i+k) && j < 2)
{
for(int v : G[u])
if(v != fa)
f[u][i][j][k] += min(min(f[v][1][i][0],f[v][1][i][1]),f[v][0][i][1]);
}
else f[u][i][j][k] += dp[t][0];
}
}
int main()
{
while(~scanf("%d%d%d",&n,&c1,&c2) && (n+c1+c2))
{
for(int i = 1;i <= n;i++) G[i].clear();
for(int i = 1;i < n;i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
cout<<min(min(min(f[1][0][0][1],f[1][0][0][0]),min(f[1][1][0][1],f[1][1][0][0])),min(f[1][2][0][1],f[1][2][0][0]))<<endl;
}
}