#P2058. 全国动员
#P2058. 全国动员
题目描述
X国有
输入格式
第一行是2个整数
接下来n-1行,每行3个整数
接下来是
输出格式
一个整数,表示答案,范围在int范围
样例
输入数据 1
6 3
1 2 1
1 3 1
2 4 1
2 5 1
3 6 1
3 4 3
3 2 5
6 1 2
1 8 9
8 8 1
4 7 6
输出数据 1
7
数据规模与约定
50%的数据有 n<=10, m<=5。
100%数据n<=55, m<=11,保证 n>=m。
Solution
刚看到这道题以为是一道正常的树形
从
设 __builting_popcount(i)==1
(
然后需要思考的就是对于非叶节点的转移。很明显,非叶节点应该有两个状态来源:
自己不做任务
对于这一种情况,
因为我们是一个一个向下
自己做一个任务
这种情况在上一种情况的基础上其实很好转移。假设当前结点
开始前初始化 0x7fffffff
,会导致加法计算时溢出,导致答案变成负数,然后喜提 (当然如果你要用 。另外需要注意,
另外,在代码实现的时候,需要注意上面
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<limits.h>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
template<typename T> void read(T &k)
{
k=0;
T flag=1;char b=getchar();
while (b<'0' || b>'9') {flag=(b=='-')?-1:1;b=getchar();}
while (b>='0' && b<='9') {k=(k<<3)+(k<<1)+(b^48);b=getchar();}
k*=flag;
}
const int _SIZE=55,_STATSIZE=(1<<11);
int n,m;
struct EDGE{
int next,to,len;
}edge[(_SIZE<<1)+5];
int tot,head[_SIZE+5],InDe[_SIZE+5];
void AddEdge(int x,int y,int v)
{
++tot;
edge[tot].next=head[x];
edge[tot].to=y;
edge[tot].len=v;
InDe[y]++;
head[x]=tot;
}
int f[_SIZE+5][_STATSIZE+5];
int cost[_SIZE+5][_SIZE+5];
void dfs(int x,int fa)
{
for (int i=head[x];i;i=edge[i].next)
{
int twd=edge[i].to,c=edge[i].len;
if (twd==fa) continue;
dfs(twd,x);
for (int i=(1<<m)-1;i;i--)
for (int t=i;t;t=(t-1)&i)
{
f[x][i]=min(f[twd][t]+f[x][i^t]+c,f[x][i]);
}
}
for (int i=(1<<m)-1;i;i--)
for (int k=0;k<m;k++)
if (i>>k&1) f[x][i]=min(f[x][i],f[x][i^(1<<k)]+cost[x][k+1]);
}
int main()
{
read(n),read(m);
for (int i=1;i<n;i++)
{
int a,b,c;
read(a),read(b),read(c);
AddEdge(a,b,c);
AddEdge(b,a,c);
}
for (int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
read(cost[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<1<<m;j++)
f[i][j]=INT_MAX>>2;//防止溢出
dfs(1,0);
printf("%d\n",f[1][(1<<m)-1]);
return 0;
}
又是一道树形状压
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步