zoukankan      html  css  js  c++  java
  • poj 1463 Strategic game

    http://poj.org/problem?id=1463

    有两种做法,一种是二分图,一种是树形DP,这里两种都做了。

    二分图的。

    就是经典的二分图最小点覆盖,要选取最小的点,使得所有的边与这些点关联,(可以一条边关联两个点,为了需要哟)

    那么我们建的是无向边,因为可以互相关联,还是利用经典的拆点思想,

    本来要若原图中i与j有边。我们要连的是i到j+n,j到i+n,但这样连的效果和i与j连,j与i连是一样的。所以为了节省空间,我们这样连

    然后就是匈牙利算法,求最小点覆盖=最大匹配数

    View Code
    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #define maxn 2000
    using namespace std;
    vector<int>node[maxn];
    int mm[maxn];
    int visit[maxn];
    int n;
    int dfs(int fa)
    {
        for(int i=0;i<node[fa].size();i++)
        {
            int v=node[fa][i];
            if(!visit[v])
            {
                visit[v]=1;
                if(mm[v]==-1||dfs(mm[v]))
                {
                    mm[v]=fa;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    void solve()
    {
         int cnt=0;
         memset(mm,-1,sizeof(mm));
         for(int i=0;i<n;i++)
         {
             memset(visit,0,sizeof(visit));
             if(dfs(i)) cnt++;
         }
         cout<<cnt/2<<endl;
    //因为连的是双向边,所以求的的匹配数是所需答案的2倍
    }
    int main()
    {
    
        int u,num;
        int v;
        while(cin>>n)
        {
            for(int i=0;i<=n;i++)
                node[i].clear();
            for(int i=0;i<n;i++)
            {
                scanf("%d:(%d)",&u,&num);//这个读入要注意
                while(num--)
                {
                    cin>>v;
                    node[u].push_back(v);//要连双向边
                    node[v].push_back(u);
                }
            }
            solve();
        }
        return 0;
    }

    树形DP

    用DP[I][0]来表示该点没有放兵,以这个点为根的子树所需的最少兵数。

    用DP[I][1]来表示该点有放兵,以这个点为根的子树所需的最少兵数。

    那么可以得到状态方程

    dp[fa][0]+=dp[son][1];//如果该父亲不放,那么儿子必须放
    dp[fa][1]+=min(dp[son][0],dp[son][1]);//如果该父亲放,儿子在放和不放之间选择最小的

    访问的时候,因为要先知道儿子的信息,所以类似于后续遍历

    View Code
    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #define maxn 100000
    using namespace std;
    int dp[maxn][2];
    int n;
    int root;
    vector<int>node[maxn];
    void init()
    {
        int u,v,num;
        root=-1;
        for(int i=0;i<=n;i++)
            node[i].clear();
        for(int i=0;i<n;i++)
        {
            scanf("%d:(%d)",&u,&num);//读入要注意
            if(root==-1)root=u;//第一个点是根
            while(num--)
            {
                cin>>v;
                node[u].push_back(v);//连有向边
            }
        }
    }
    int solve(int fa)
    {
        dp[fa][0]=0;dp[fa][1]=1;
        for(int i=0;i<node[fa].size();i++)
        {
            int son=node[fa][i];
            solve(son);
    //其实觉得类似于后续遍历,因为父亲要用到儿子的信息,
    //所以要先知道儿子的
            dp[fa][0]+=dp[son][1];//如果该父亲不放,那么儿子必须放
            dp[fa][1]+=min(dp[son][0],dp[son][1]);
    //如果该父亲放,儿子在放和不放之间选择最小的
        }
        return min(dp[fa][0],dp[fa][1]);
    }
    int main()
    {
        while(cin>>n)
        {
            init();
            printf("%d\n",solve(root));//
        }
        return 0;
    }
  • 相关阅读:
    (转)JAVA国际化
    (转)实现这两个接口ModelDriven<T>,Preparable有什么用?
    cordova 与 phonegap关系
    NApache+JBOSS架构方案
    (转)Java 标注(Annotation)详解
    Jboss集群(五)--F5硬件负载均衡器双击热备 + Jboss集群终极实现
    GTK+/GNOME编程(一)
    二维数组中查找指定的数
    计算字符串距离
    统计指定数字的个数,并将其按权值10的次方数相加
  • 原文地址:https://www.cnblogs.com/cs1003/p/2662983.html
Copyright © 2011-2022 走看看