zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    linux 解压tgz 文件指令
    shell 脚本没有执行权限 报错 bash: ./myshell.sh: Permission denied
    linux 启动solr 报错 Your Max Processes Limit is currently 31202. It should be set to 65000 to avoid operational disruption.
    远程查询批量导入数据
    修改 MZTreeView 赋权节点父节点选中子节点自动选中的问题
    关于乱码的问题解决记录
    我的网站优化之路
    对设计及重构的一点反思
    我的五年岁月
    奔三的路上
  • 原文地址:https://www.cnblogs.com/nanke/p/2384269.html
Copyright © 2011-2022 走看看