zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 187 F

    差亿点AK,只怪没学过状态压缩动态规划,呀嘞呀嘞dazei
    学到状压DP的一个操作
    枚举一个图的子图:

    for(int i=n;i;i=(i-1)&n)
    {
          //i就是n的子图
    }
    

    n的子图关于n的补图

    n;   //原图
    m;   //n的子图
    m^n; //m关于n的补图
    

    AtCoder Beginner Contest 187 F - Close Group

    题意:给一个n(n<=18)节点m条边的图,删除几个边后,使它变成几个连通子图,求最少能够变成几个子图,并且全是完全图
    题解:首先枚举所有子图,如果是完全图,标记dp[i]=1,然后从小到大枚举,对一个非完全子图,再枚举其子图更新答案,由于是从小到大枚举,因此当前子图的子图肯定已经更新完了,所以可放心dp

    #include<bits/stdc++.h>
    using namespace std;
    #define f(i,a,b) for(register int i=a;i<=b;++i)
    #define ll long long
    #define pb push_back
    inline int read(){int x;scanf("%d",&x);return x;}
    int eg[20][20],dp[1<<N];
    void solve()
    {
    	int n=read(),m=read();
    	f(i,1,m){
    		int x=read(),y=read();
    		eg[x][y]=eg[y][x]=1;
    	}
    	int sum=(1<<n)-1;
    	dp[0]=999999;
    	for(int i=1;i<=sum;++i) //找出所有完全子图
    	{
    		vector<int>edge;
    		for(int j=0;j<n;j++) if(i&(1<<j)) edge.pb(j+1);
    		int flag=1;
    		for(int j=0;flag&&j<edge.size();++j)
    			for(int k=j+1;flag&&k<edge.size();++k)
    				if(!eg[edge[j]][edge[k]]) flag=0;
    		if(flag) dp[i]=1;
    		else dp[i]=999999; 
    	}
    	for(int i=1;i<=sum;++i)
    	{
    		if(dp[i]==1) continue;
    		for(int j=i;j;j=(j-1)&i) //枚举子图,用dp[j]+dp[j^i]更新答案
    		{
    			dp[i]=min(dp[i],dp[j]+dp[j^i]);
    		}
    	}
    	cout<<dp[sum]<<endl;
    }
    int main()
    {
    	int T=1;
    	while(T--) solve();
    	return 0;
    } 
    
    

    再补几题状压DP
    1:P1433恰奶酪
    题意:给二维坐标上的n(n<=18)个点,从(0,0)出发经过所有点的最小距离
    题解:dp[i][j]代表状态压缩为i的时候最后一个奶酪吃的是第j个奶酪的最小移动距离,对于一个状态,枚举最后一个点,枚举到的每个点再枚举上一个点来更新当前状态

    #include<bits/stdc++.h>
    using namespace std;
    #define f(i,a,b) for(register int i=a;i<=b;++i)
    #define ll long long
    #define N 18
    #define INF 999999999
    #define pb push_back
    inline int read(){int x;scanf("%d",&x);return x;}
    double dp[1<<N][N],x[N],y[N];
    int BitCount(int n)//求n二进制下1的个数 
    {
       	int c =0 ;
        for (c =0; n; ++c)
        {
            n &= (n -1) ; 
        }
        return c ;
    }
    double dis(int a,int b)//距离 
    {
    	return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
    }
    void solve()
    {
    	int n=read();
    	f(i,0,n-1)
    		cin>>x[i]>>y[i];
    	int sum=(1<<n)-1;
    	for(int i=1;i<=sum;++i)
    	{
    		f(j,0,n-1) dp[i][j]=INF;
    		if(BitCount(i)==1) {	//如果状态只有一个点那就是到(0,0)的距离 
    			for(int j=0;j<n;++j) if((1<<j)&i) {
    				dp[i][j]=dis(n,j);
    				break;
    			}
    			continue;
    		}
    		for(int j=0;j<n;++j)    //枚举最后一个点 
    		{
    			if(!((1<<j)&i)) continue;
    			for(int k=0;k<n;++k)//枚举连接最后一个点的上一个点来更新答案 
    			{
    				if(!((1<<k)&i)) continue;
    				if(j==k) continue;
    				dp[i][j]=min(dp[i][j],dp[i&(~(1<<j))][k]+dis(k,j));
    			}
    		}
    	}
    	double ans=99999999;
    	f(i,0,n-1) ans=min(ans,dp[sum][i]); 
    	printf("%.2lf",ans);
    }
    int main()
    {
    	int T=1;
    	while(T--) solve();
    	return 0;
    } 
    
  • 相关阅读:
    (12)springboot打war包-copy
    基于Python在MacOS上安装robotframework-ride
    mac终端输入python默认打开python3
    win10 切换网卡的bat
    PyCharm2018激活码
    我告诉你 ,一个 window免费系统下载的网站!
    oracle 子查询的几个种类
    trunc()
    case when then else end 与 decode 的区别
    触发器 of oracle
  • 原文地址:https://www.cnblogs.com/Tiork/p/14224998.html
Copyright © 2011-2022 走看看