牛客訓練(狀壓DP)
有想到要狀壓可是不知道要用壓縮後的狀態來表示什麼,題還是做太少了。。
設d[S]表示已經選擇S的情況下的最小衝突(即以後再選的優先順序都要比S裡面的都小),這樣轉移的時候只要列舉S的子集,分離成原有的子集V和後加的子集T合併成S這樣來轉移就行了。。
列舉的複雜度計算可以根據集合的size分類計算,所以是
然而轉移的時候計算比較複雜,一方面是T自己和自己優先順序相同的衝突,一個是V和T的衝突,如果暴力列舉複雜度相當高,不過可以先預處理一下,自己和自己衝突的容易處理,然而直接預處理集合之間的衝突需要的複雜度是O(4^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]); }
資料排序
時間限制: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