topcoder srm 696 div1 -3

1、给定一个50个节点的无向图,有$m$条边。现在以任意一种序列对每个节点染色。染当前节点的代价为染色完当前节点后满足两个端点都被染色的边的数量。求最小的染色代价。$m \leq 20$

思路:一个直观的思路是应该先染色度数小的节点。由于$m\leq 20$,所以如果先把那些孤立的点以及那些度数为1但是其相连的另一端还未染色的节点先染色,那么剩下还未染色的节点数不会超过20。而且已经染色的节点代价都为0.令$c_{s}$表示将状态为$s$的节点全部染色时最后一步的代价。$f_{i}$表示将状态$i$全部染色的代价,那么$f_{i}=min(f_{t}+c_{i})$,其中$t=i$^$2^{j}$且$i$&$2^{j}\neq 0$,即最后染色节点$j$

#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <string.h>
#include <set>
#include <vector>
#include <time.h>
#include <queue>
#include <stack>
#include <map>
#include <assert.h>
using namespace std;



const int N=50;

int h[N];
int a[N],aNum;
int d[N];
int cost[1<<23];
int dp[1<<23];


int GetCost(const int Mask,const vector<int>& Ex,const vector<int>& Ey)
{
    int p[N];
    memset(p,0,sizeof(p));
    for(int i=0;i<50;++i)
    {
        if(h[i]) p[i]=1;
        else if(Mask&(1<<a[i])) p[i]=1;
    }
    int nNum=0;
    const int m=(int)Ex.size();
    for(int i=0;i<m;++i)
    {
        if(p[Ex[i]]&&p[Ey[i]]) ++nNum;
    }
    return nNum;
}

class Gperm
{
public:
    int countfee(vector<int> x,vector<int> y)
    {
        const int m=(int)x.size();
        const int n=50;
        for(int i=0;i<m;++i) ++d[x[i]],++d[y[i]];
        for(int i=0;i<n;++i)
        {
            if(0==d[i]) h[i]=1;
            else if(1==d[i])
            {
                int j;
                for(int k=0;k<m;++k)
                {
                    if(x[k]==i) j=y[k];
                    else if(y[k]==i) j=x[k];
                }
                if(!h[j]) h[i]=1;
            }
        }
        for(int i=0;i<n;++i) if(!h[i]) a[i]=aNum++;
        for(int i=0;i<(1<<aNum);++i) cost[i]=GetCost(i,x,y);

        memset(dp,-1,sizeof(dp));
        dp[0]=0;
        for(int i=1;i<(1<<aNum);++i)
        {
            for(int j=0;j<aNum;++j) if(i&(1<<j))
            {
                int tmp=dp[i^(1<<j)]+cost[i];
                if(dp[i]==-1||tmp<dp[i]) dp[i]=tmp;
            }
        }
        return dp[(1<<aNum)-1];

    }
};

2、给定一个$n$个节点的无向图,其中有些边是不确定的,可能有也可能没有。这样的边有$k$条。所以不同的图有 $2^{k}$种。第$i$种图的的最大团的大小为$f_{i}$,求所有$f_{i}$的和。

思路:枚举每一种图计算其最大团。首先枚举最大团中包含的最小顶点$x$,那么剩下的点的选择范围一定是$[x+1,n-1]$中跟$x$有边的点,设这些组成的集合为$S_{1}$。那么从小到大枚举$S_{1}$中的点作为最大团中的点,然后会得到新的集合$S_{2}$,依次类推。

#include <stdio.h>
#include <string>
#include <stack>
#include <vector>
#include <string.h>
#include <algorithm>
using namespace std;




class Clicounting
{
    int nBestAns;
    int n;
    long long a[50];

    int Get(long long x)
    {
        int cnt=0;
        while(x)
        {
            ++cnt;
            x=x&(x-1);
        }
        return cnt;
    }

    int dfs(long long Mask,int nCurSize)
    {
        if(Mask==0)
        {
            if(nCurSize>nBestAns)
            {
                nBestAns=nCurSize;
                return 1;
            }
            return 0;
        }
        int Pre=0;
        while(Mask!=0)
        {
            if(nCurSize+Get(Mask)<=nBestAns) return 0;
            while(Pre<n&&!(Mask&(1ll<<Pre))) ++Pre;
            Mask^=1ll<<Pre;
            if(dfs(Mask&a[Pre],nCurSize+1)) return 1;
        }
        return 0;
    }

public:
    int count(vector<string> g)
    {
        n=(int)g.size();
        vector<pair<int,int> > V;
        int mp[50][50];
        for(int i=0;i<n;++i) for(int j=i+1;j<n;++j)
        {
            if(g[i][j]=='?')
            {
                V.push_back(make_pair(i,j));
                mp[i][j]=mp[j][i]=(int)V.size()-1;
            }
        }
        int nAns=0;
        const int M=(int)V.size();
        for(int i=0;i<(1<<M);++i)
        {
            memset(a,0,sizeof(a));
            for(int x=0;x<n;++x) for(int y=x+1;y<n;++y)
            {
                if(g[x][y]=='1') a[x]|=1ll<<y,a[y]|=1ll<<x;
                else if(g[x][y]=='?')
                {
                    if(i&(1<<mp[x][y])) a[x]|=1ll<<y,a[y]|=1ll<<x;
                }
            }
            nBestAns=0;
            for(int x=n-1;x>=0;--x)
            {
                long long b=0;
                for(int y=x+1;y<n;++y) b|=1ll<<y;
                dfs(b&a[x],1);
            }
            nAns+=nBestAns;
        }
        return nAns;
    }
};

  

posted @ 2017-05-19 12:03  朝拜明天19891101  阅读(326)  评论(0编辑  收藏  举报