HDU 6149 Valley Numer II (揹包+狀壓+滾動陣列)
阿新 • • 發佈:2018-12-17
#include<bits/stdc++.h> using namespace std; #define debug puts("YES"); #define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++) #define ll long long #define lrt int l,int r,int rt #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define root l,r,rt #define mst(a,b) memset((a),(b),sizeof(a)) const int maxn =30+5; const int mod=1e9+7; const int ub=10000; void gmax(int& x,int y) {if(y>x) x=y;} ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;} ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} /* 題目大意:給定一個圖, 事先標出一些高點,然後穩有多少個三元組滿足, 一低二高,低和高之間有邊相連。 每個點只能屬於這一個三元組。 對每個低點進行揹包,選擇的集合是當前低點的邊集合, 因為k只有15所以對k進行狀壓(再加一層下標對映), 揹包裡面一層是普通的狀壓,不過要考慮當前更新過的不能重複使用, 所以犧牲點空間進行滾動陣列。 (剛開始還不以為需要滾動陣列,注意對於一個單一點有多種二元組選擇。) */ int n,m,k,x,y; int dp[2][1<<16],vis[40]; int a[20],mp[100]; vector<int> g[maxn]; int main() { int t;scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&k); for(int i=0;i<n;i++) g[i].clear(); for(int i=0;i<m;i++) { scanf("%d%d",&x,&y);x--,y--; g[x].push_back(y),g[y].push_back(x);/// } mst(vis,0);mst(mp,0); int s=0;///總狀態 for(int i=0;i<k;i++) { scanf("%d",&a[i]); a[i]--;vis[a[i]]=1; mp[a[i]]=i;///對映 } s=(1<<k)-1; int now=0; mst(dp,-1);dp[now][s]=0;///當前狀態為零 for(int i=0;i<n;i++) if(vis[i]==0){///挑選那些低點 now^=1;memcpy(dp[now],dp[now^1],sizeof(dp[now])); for(int j=0;j<g[i].size();j++) { if(vis[g[i][j]]==0) continue; for(int q=j+1;q<g[i].size();q++)///選擇點對 { if(vis[g[i][q]]==0) continue; int tmp=(1<<mp[g[i][j]])+(1<<mp[g[i][q]]); for(int p=0;p<(1<<k);p++) if((p&tmp)==tmp && dp[now^1][p]!=-1) dp[now][p^tmp]=max(dp[now][p^tmp],dp[now^1][p]+1); } } } int ans=0;for(int i=0;i<(1<<k);i++) gmax(ans,dp[now][i]); printf("%d\n",ans); } return 0; }