• hdu 2415 Bribing FIPA(树形DP)


    题意:给定N个国家,相互之间可能存在附属关系,现在想要贿赂m个国家,已知,贿赂一个国家,那么如果该国家拥有附属国,那么他的所有附属国都可以算作已经贿赂。

    分析:按照国家之间的附属关系连边(有向),之后将森林转为一棵树,就变成了一棵树上的01背包了。

    因为国家是用名字给出的,先用字典树给名字编号……

    dp[i][j]表示第i个国家及其附属国中选j个国家的最小花费

    之前一直过不了的题,现在居然1A了,主要是思路比较清晰

    View Code
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<string>
    #include<vector>
    using namespace std;
    const int N = 210;
    int n,num,m,dp[N][N],w[N],in[N];
    char s[20110];
    bool vis[N];
    vector<int> g[N];
    typedef struct node
    {
    int cnt;
    struct node *next[52];
    }*tree,Trie;
    tree root;
    inline int GetNum(char *t){
    tree p = root,newnode;
    for(int i = 0;i < strlen(t); ++i){
    int u = t[i] - 'a';
    if(u<0) u=t[i]-'A'+26;
    if(p->next[u]==NULL)
    {
    newnode=(tree)malloc(sizeof(Trie));
    newnode->cnt=-1;
    for(int j=0;j<52;j++)
    newnode->next[j]=NULL;
    p->next[u]=newnode;
    p=newnode;
    }
    else
    p = p->next[u];
    }
    if(p->cnt == -1) //该节点未出现过
    p->cnt = num ++;
    return p->cnt;
    }
    void init()
    {
    root=(tree)malloc(sizeof(Trie));
    root->cnt=-1;
    for(int j=0;j<52;j++)
    root->next[j]=NULL;
    num=1;
    memset(in,0,sizeof(in));
    for(int i=0;i<=n;i++)
    g[i].clear();
    for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++)
    dp[i][j]=INT_MAX;
    }
    int dfs(int u)
    {
    int size=g[u].size();
    dp[u][0]=0;
    int t=0;
    for(int i=0;i<size;i++)
    {
    int v=g[u][i];
    int now=dfs(v);
    for(int j=t;j>=0;j--)//当前z树选择j个点
    {
    for(int k=0;k<=now;k++)//以v为根的子树选择k个点
    dp[u][j+k]=min(dp[u][j+k],dp[u][j]+dp[v][k]);
    }
    t+=now;
    }
    for(int i=1;i<=t+1;i++)//注意,这里就是题目的关键了,如果选择了父节点,那么父节点可以当成子树的所有状态值
    dp[u][i]=min(dp[u][i],w[u]);
    return t+1;
    }
    int main()
    {
    char str[100],c[110];
    while(scanf("%s",str)==1)
    {
    if(strcmp(str,"#")==0)
    break;
    n=atoi(str);
    scanf("%d",&m);
    getchar();
    init();
    for(int i=0;i<n;i++)
    {
    gets(s);
    int len=strlen(s),cc=0,t=0,a,b;
    for(int j=0;j<=len;j++)
    {
    if(s[j]!=' ' && s[j]!='\0')
    c[t++]=s[j];
    if(s[j]==' '||s[j]=='\0')
    {
    cc++;
    c[t]='\0';
    t=0;
    if(cc==1)
    a=GetNum(c);
    else if(cc==2)
    w[a]=atoi(c);
    else {
    b=GetNum(c);
    g[a].push_back(b);
    in[b]++;
    }
    }
    }
    }
    for(int i=1;i<=n;i++)//将森林转为树
    {
    if(in[i]==0)
    g[0].push_back(i);
    }
    w[0]=INT_MAX;//0节点是自己添加的,它对应的花费应该设定为正无穷,这样就不会选择这个点了
    dfs(0);
    printf("%d\n",dp[0][m]);
    }
    return 0;
    }
  • 相关阅读:
    蓝绿发布、灰度发布和滚动发布
    centos网卡配置修改
    服务器安装centos8提示显示器不支持输出的分辨率
    Linux软件包管理
    Redis (error) NOAUTH Authentication required.解决方法
    mysql5.7.35数据库迁移
    MySQL5.7的参数优化
    mysql 安装完以后没有mysql服务
    Promise结合setTimeout--promise练习题(2)
    基础题--promise练习题(1)
  • 原文地址:https://www.cnblogs.com/nanke/p/2384269.html
Copyright © 2020-2023  润新知