二分图 hdu 1054 Strategic Game

来源:互联网 发布:oracle数据库分页查询 编辑:程序博客网 时间:2024/06/08 18:36

这是个最小点覆盖问题,而最小点覆盖问题=二分图最大匹配数

匈牙利算法是计算二分图最大匹配的算法:

其dfs实现版本如下

bool dfs(int v){    for(vector<int>::iterator it=tree[v].begin();it!=tree[v].end();it++){        int w=*it;        //for        if(!visited[w]){            visited[w]=true;            if(match[w]==-1||dfs(match[w])){                //  the import is only set match[w]=v                // don't seet match[v]=w                match[w]=v;                return true;            }        }    }    return false;}int hungarian(){    int ans=0;     memset(match,-1,sizeof(match));    for(int v=0;v<n;v++){            //reset visited            memset(visited,false,sizeof(visited));            if(dfs(v)){                ans++;            }    }    return ans;}

完整1054 二分图解法代码如下:

#include <iostream>#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<vector>#include<algorithm>using namespace std;#define MAX 1505bool visited[MAX];int match[MAX];//int  tree[MAX][MAX];int n;int soldier=0;vector<int> tree[MAX];bool dfs(int v){    for(vector<int>::iterator it=tree[v].begin();it!=tree[v].end();it++){        int w=*it;        //for        if(!visited[w]){            visited[w]=true;            if(match[w]==-1||dfs(match[w])){                //  the import is only set match[w]=v                // don't seet match[v]=w                match[w]=v;                return true;            }        }    }    return false;}int hungarian(){    int ans=0;     memset(match,-1,sizeof(match));    for(int v=0;v<n;v++){            //reset visited            memset(visited,false,sizeof(visited));            if(dfs(v)){                ans++;            }    }    return ans;}int main(){    while(cin>>n){      int t=n;      soldier=0;       for(int i=0;i<n;i++){         tree[i].clear();       }       memset(visited,false,sizeof(visited));       while(t--){            int v;            int r;            scanf("%d:(%d)",&v,&r);            int tmp=0;            for(int i=0;i<r;i++){                cin>>tmp;                tree[v].push_back(tmp);                tree[tmp].push_back(v);            }       }        if(n==1){            soldier=1;        }else{            soldier=hungarian()/2;        }       printf("%d\n",soldier);    }    return 0;}

这道题同时还有树形dp解法:

dp[i][0] 表示该节点不放士兵的值(意味着所有子节点必须放士兵,否则子节点不能被照看到),不难得出,dp[i][0] 等于 sum(dp[j][1]) j是i的所有连接点中的一个
dp[i][1] 表示该节点放士兵的值, (子节点可以放,也可以不放),dp[i][1]= sum(min(dp[j][0],dp[j][1]))+1, 意识就是对i的所有子节点,把节点的士兵的最小值进行相加,最后加上节点本身放1个士兵

最后的结果就是 min(dp[root][0],dp[root][1]);

树形dp代码:

void dfs(int i){    if(visited[i]) return ;    visited[i]=true;    dp[i][0]=0;    dp[i][1]=1;    for(vector<int>::iterator iter=tree[i].begin();iter!=tree[i].end();iter++){        if(visited[*iter])continue;        dfs(*iter);        dp[i][0]+=dp[*iter][1];        dp[i][1]+=MIN(dp[*iter][0],dp[*iter][1]);      //  cout<<"the i is: "<<i<<"  "<<" true is: "<<dp[i][1]<<" false is  "<<dp[i][0]<<endl;    }    return ;}
原创粉丝点击