zoukankan      html  css  js  c++  java
  • JZOJ 6316. djq的朋友圈(状压DP)

    JZOJ 6316. djq的朋友圈

    题目

    Description

    在这里插入图片描述

    Input

    在这里插入图片描述

    Output

    一个整数表示最多的盟友数。

    Sample Input

    Sample 1:
    7 8
    1 2 0
    1 3 0
    2 4 0
    4 5 0
    3 4 1
    2 5 1
    5 7 1
    1 7 1

    Sample 2:
    8 24
    5 8 1
    6 3 1
    2 8 0
    4 6 1
    4 1 1
    2 3 1
    5 4 1
    5 1 0
    2 6 0
    1 3 0
    8 7 1
    8 4 1
    1 7 1
    7 2 1
    8 1 1
    3 4 0
    3 7 0
    7 6 0
    5 2 0
    6 1 1
    5 3 0
    5 7 1
    6 5 0
    6 8 0

    Sample Output

    Sample 1:
    4

    Sample 2:
    3

    Data Constraint

    在这里插入图片描述
    在这里插入图片描述

    Hint

    样例1 中,如果顺序为“7,2,3”,可以使得 2,3,4,5 都和 djq 成为盟友。

    题解

    • 这题的题意看起来有点复杂。。。
    • 首先可以发现,与 1 1 1最短距离大于 2 2 2的点最后一定是不确定的,所以忽略它们,
    • 设集合 A A A为所有与 1 1 1有边相连的点,也就是最初已经确定的,
    • 集合 B B B为所有在 A A A集合外且不为 1 1 1的与 A A A集合任意点相邻的点,也就是能间接确定的,
    • 其它的都没法确定。
    • 现在只用考虑从 A A A集合中选点的顺序,
    • 对于 70 % 70\% 70%的数据,直接状压当前 A A A集合中已经选过的点,
    • 每次枚举一个状态,将已经选过的点所能连向的所有在 B B B中的点标记,标记的就是被确定关系的
    • 再枚举一个还没选过的点,它所连向所有在的 B B B中的点,如果还未被标记的点即可以确定关系,统计出有多少个“盟友”,更新状态。
    • 最后还要再加上 A A A集合中的“盟友”。
    • 对于全部数据,做法也是类似的,
    • 如果 A A A集合小于 B B B集合大小,同 70 % 70\% 70%的做法,
    • 否则状压 B B B中的点,做法类似,
    • 还是枚举 A A A中的点,但不用判断它是否选过,只需要看它能确定多少 B B B中的点,然后更新状态。
    • 最后仍然要加上 A A A集合中的“盟友”。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int last[45],next[1800],to[1800],re[1800],len=0;
    int nu[45],bz[45],f[2100000];
    int p[45],s1[45],s2[45],r[45][45];
    void add(int u,int v,int x)
    {
    	to[++len]=v;
    	re[len]=x;
    	next[len]=last[u];
    	last[u]=len;
    	r[u][v]=x;
    }
    int main()
    {
    	int n,m,i,j,k,u,v,x;
    	scanf("%d%d",&n,&m);
    	memset(r,255,sizeof(r));
    	for(i=1;i<=m;i++)
    	{
    		scanf("%d%d%d",&u,&v,&x);
    		add(u,v,x),add(v,u,x);
    	}
    	s1[0]=s2[0]=0;
    	for(i=last[1];i;i=next[i]) bz[to[i]]=1,s1[++s1[0]]=to[i],nu[to[i]]=s1[0];
    	for(i=1;i<=n;i++) if(bz[i]==1)
    		for(j=last[i];j;j=next[j]) if(!bz[to[j]]&&to[j]>1) bz[to[j]]=2,s2[++s2[0]]=to[j],nu[to[j]]=s2[0];
    	if(s1[0]<21)
    	{
    		memset(f,0,sizeof(f));
    		for(i=0;i<(1<<s1[0]);i++) if(i==0||f[i])
    		{
    			memset(p,0,sizeof(p));
    			for(j=1;j<=s1[0];j++) if(i&(1<<(j-1))) 
    				for(k=last[s1[j]];k;k=next[k]) if(bz[to[k]]==2) p[to[k]]=i+1;
    			for(j=1;j<=s1[0];j++) if((i&(1<<(j-1)))==0)
    			{
    				int s=0;
    				for(k=last[s1[j]];k;k=next[k]) if(bz[to[k]]==2&&p[to[k]]<=i) s+=r[1][s1[j]]==re[k];
    				f[i+(1<<(j-1))]=max(f[i+(1<<(j-1))],f[i]+s);
    			}
    		}	
    		int s=0;
    		for(i=1;i<=s1[0];i++) s+=!r[1][s1[i]];
    		printf("%d
    ",f[(1<<s1[0])-1]+s);
    	}
    	else
    	{
    		memset(f,0,sizeof(f));
    		for(i=0;i<(1<<s2[0]);i++) if(i==0||f[i])
    		{
    			for(j=1;j<=s1[0];j++) 
    			{
    				int s=0,t=0;
    				for(k=last[s1[j]];k;k=next[k]) 
    					if(bz[to[k]]==2&&!(i&(1<<(nu[to[k]]-1)))) s+=r[1][s1[j]]==re[k],t+=1<<(nu[to[k]]-1);
    				f[i+t]=max(f[i+t],f[i]+s);
    			}
    		}
    		int s=0;
    		for(i=1;i<=s1[0];i++) s+=!r[1][s1[i]];
    		printf("%d
    ",f[(1<<s2[0])-1]+s);
    	}
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    matlab矩阵中如何去掉重复的行;如何找到相同的行,并找到其位置
    Coursera 机器学习 第9章(下) Recommender Systems 学习笔记
    机器学习基石笔记1——在何时可以使用机器学习(1)
    Coursera 机器学习 第9章(上) Anomaly Detection 学习笔记
    matlab安装过程的被要求的配置程序
    jdk环境变量配置
    Coursera 机器学习 第8章(下) Dimensionality Reduction 学习笔记
    Coursera 机器学习 第8章(上) Unsupervised Learning 学习笔记
    Coursera 机器学习 第7章 Support Vector Machines 学习笔记
    linux服务器---squid限制
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910064.html
Copyright © 2011-2022 走看看