牛客训练(状压DP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qkoqhh/article/details/82953298

有想到要状压可是不知道要用压缩后的状态来表示什么,题还是做太少了。。

设d[S]表示已经选择S的情况下的最小冲突(即以后再选的优先级都要比S里面的都小),这样转移的时候只要枚举S的子集,分离成原有的子集V和后加的子集T合并成S这样来转移就行了。。

枚举的复杂度计算可以根据集合的size分类计算,所以是O(\sum C_n^k2^{n-k})=O(3^n)

然而转移的时候计算比较复杂,一方面是T自己和自己优先级相同的冲突,一个是V和T的冲突,如果暴力枚举复杂度相当高,不过可以先预处理一下,自己和自己冲突的容易处理,然而直接预处理集合之间的冲突需要的复杂度是O(4^n),所以只能求一下一个元素和一个集合之间的冲突,然后转移的时候枚举一下当前元素的冲突即可。。

因此总复杂度为O(n^22^n+n3^n)

然后看别人代码学到了枚举子集的姿势,得学一下(自己是直接写搜索枚举的,比较麻烦)

解法一:

/**
 *        ┏┓    ┏┓
 *        ┏┛┗━━━━━━━┛┗━━━┓
 *        ┃       ┃  
 *        ┃   ━    ┃
 *        ┃ >   < ┃
 *        ┃       ┃
 *        ┃... ⌒ ...  ┃
 *        ┃       ┃
 *        ┗━┓   ┏━┛
 *          ┃   ┃ Code is far away from bug with the animal protecting          
 *          ┃   ┃   神兽保佑,代码无bug
 *          ┃   ┃           
 *          ┃   ┃        
 *          ┃   ┃
 *          ┃   ┃           
 *          ┃   ┗━━━┓
 *          ┃       ┣┓
 *          ┃       ┏┛
 *          ┗┓┓┏━┳┓┏┛
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛
 */ 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<stdlib.h>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y)/2
#define NM 17 
#define nm 40005
#define pi 3.1415926535897931
const int inf=1e9+7;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar() ;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}




int n,tot,p[NM],a[NM][NM],_x,_y,d[nm],b[NM][nm],c[nm];



int main(){
    n=read();tot=succ(n)-1;p[0]=1;
    inc(i,1,n)p[i]=p[i-1]<<1;
    inc(i,1,2*n*(n-1)){_x=read();_y=read();a[_x][_y]++;}
    inc(k,1,tot)inc(i,1,n)if(p[i-1]&k)inc(j,i+1,n)if(p[j-1]&k)c[k]+=abs(a[i][j]-a[j][i]);
    inc(i,1,n)inc(k,1,tot)if(!(k&p[i-1]))inc(j,1,n)if(k&p[j-1])b[i][k]+=a[j][i];
    inc(i,1,tot)d[i]=inf;
    inc(i,1,tot)for(int t=i;t;t=(t-1)&i){
	int s=0;
	inc(j,1,n)if(t&succ(j-1))s+=b[j][i^t];
	d[i]=min(d[i],d[i^t]+s+c[t]);
    }
    return 0*printf("%d\n",d[tot]);
}

解法二:

/**
 *        ┏┓    ┏┓
 *        ┏┛┗━━━━━━━┛┗━━━┓
 *        ┃       ┃  
 *        ┃   ━    ┃
 *        ┃ >   < ┃
 *        ┃       ┃
 *        ┃... ⌒ ...  ┃
 *        ┃       ┃
 *        ┗━┓   ┏━┛
 *          ┃   ┃ Code is far away from bug with the animal protecting          
 *          ┃   ┃   神兽保佑,代码无bug
 *          ┃   ┃           
 *          ┃   ┃        
 *          ┃   ┃
 *          ┃   ┃           
 *          ┃   ┗━━━┓
 *          ┃       ┣┓
 *          ┃       ┏┛
 *          ┗┓┓┏━┳┓┏┛
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛
 */ 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<stdlib.h>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y)/2
#define NM 17 
#define nm 40005
#define pi 3.1415926535897931
const int inf=1e9+7;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar() ;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}




int n,tot,p[NM],a[NM][NM],_x,_y,d[nm],b[NM][nm],c[nm],tmp,cnt;

void cal(){
    int t=tmp|cnt;int s=c[cnt]+d[tmp];
    inc(i,1,n)if(cnt&p[i-1])s+=b[i][tmp];
    d[t]=min(d[t],s);
}

void dfs(int x){
    if(x==n+1){cal();return;}
    dfs(x+1);if(!(tmp&p[x-1])){cnt^=p[x-1];dfs(x+1);cnt^=p[x-1];}
}

int main(){
    n=read();tot=succ(n)-1;p[0]=1;
    inc(i,1,n)p[i]=p[i-1]<<1;
    inc(i,1,2*n*(n-1)){_x=read();_y=read();a[_x][_y]++;}
    inc(k,1,tot)inc(i,1,n)if(p[i-1]&k)inc(j,i+1,n)if(p[j-1]&k)c[k]+=abs(a[i][j]-a[j][i]);
    inc(i,1,n)inc(k,1,tot)if(!(k&p[i-1]))inc(j,1,n)if(k&p[j-1])b[i][k]+=a[j][i];
    inc(i,1,tot)d[i]=inf;
    for(tmp=0;tmp<tot;tmp++)dfs(1);
    return 0*printf("%d\n",d[tot]);
}

链接:https://www.nowcoder.com/acm/contest/202/E
来源:牛客网
 

数据排序

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 1048576K,其他语言2097152K
64bit IO Format: %lld

题目描述

机器学习通常需要用到大量的人工标注好的数据进行训练。现在有这么一个数据集,有 N 个张照片,每张照片中都有一个模特。某个研究员想要训练一个机器学习算法,能够根据照片对模特的魅力值进行评分。为了完成这个算法,研究员找了若干个志愿者对数据做一个标注。每个志愿者每次会看到系统给出的两张照片 x 和 y,然后告诉系统他认为哪张照片的魅力值更高。例如 x 的魅力值比 y 的要高(记作 <x, y>)这样一个有序二元组称之为一个数标注。
研究员收集了若干个这样的数据标注,他想找到一组对每张照片的评分 c1, ..., cn,使得这个评分和数据的冲突越少越好。为了方便设定N 张照片所组成的 对照片都分别有 4 个记录,也就是被标注了 4 次。定义 g(x, y) 为记录<x, y>出现的次数,定义评分 {cn} 的冲突值:

你需要求出在这个数据集下冲突值 f(c) 的最小值。

输入描述:

第一行一个整数 N,表示数据集大小。
接下来 2N(N-1) 行,每一行都有两个整数 xi, yi ,表示第 i 组数据标注 < xi, yi >.

输出描述:

输出一个整数,冲突值的最小值。

示例1

输入

复制

2
1 2
1 2
2 1
1 2

输出

复制

1

说明

如果这两个数据得分相同,则冲突值为2;如果 1 比 2 得分高,则冲突值为1;如果 2 比 1 得分高,则冲突值为 3. 所以冲突值的最小值为1.

备注:

1 ≤ N ≤ 15, 1 ≤ xi,yi ≤ N, xi ≠ yi

猜你喜欢

转载自blog.csdn.net/qkoqhh/article/details/82953298