1. 程式人生 > >UVA 12035 War Map

UVA 12035 War Map

cas 搜索 bre efi 部分 DC i++ 最大 mage

技術分享圖片

技術分享圖片

讓我先把微笑送給出題人

技術分享圖片

這個題最基礎的一個想法:先找出一個度數和為總度數和的1/2的點集,然後判斷這個點集和這個點集的補集能否形成二分圖。但是就算我們把判斷的復雜度看成O(1),這個算法的復雜度也是 O(T * 2^n),根本過不了。

下面我就來列舉一下我這兩個月做的優化:

1.把度數序列排序。

這個看起來沒啥用,但是後面好多地方都要用到這個。

2.meet in the middle。

我們可以先搜出前一半的所有點集,把它們存在以它們的度數和為下標的鏈表裏;

然後我們再搜後一半,再從 以 總度數/2 - 搜出的點集度數和 為下標的鏈表裏找點集 ,然後這兩個點集加起來就是二分圖的左邊.

雖然不知道這個效果咋樣,但肯定是比直接搜點集要優很多的。

3.網絡流判斷。

這個其實不能算什麽優化,因為判斷能不能形成二分圖的時候,我實在想不到什麽其他辦法23333。

也算是開了一下腦洞把,,,,搜索+網絡流也是玄學。。。

4.詢問判重構。

直接把排完序的度數序列表示成23進制數,這樣就可以直接hash(可以用map記,因為這裏的log 是並行的不會記到復雜度裏)判重構了,如果一組詢問以前出現過那麽直接輸出以前計算出來的答案。

5.選出的點集判重構。

這個可不能用map記了,這裏如果多個log是要記在復雜度裏的,,,很可能就被卡了2333.

但稍微想一想就能發現,這個是可以用二進制表示的。我們只需要讓每種度數對應一個二進制位,並且不產生沖突即可。

比如說 1,2,2,3,5這個序列吧,我們只需要把它們的對應二進制位設成 2^0,2^1,2^1,2^3,2^4,就可以了。

6.二分圖左右點集的最大度數和點數關系。

比如說二分圖左邊的最大度數是6 ,而右邊只有5個點的話,是肯定不能形成合法二分圖的,所以我們就提前判斷而不要跑一遍網絡流。

而且感覺上述6種優化缺一不可,,,因為中間14次UNACCEPT大部分就是因為少了某種優化。。。

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
vector<int> g[35];
map<int,int> mmp;
struct lines{
	int to,flow,cap;
}l[2333];
int S,T,t,d[35],q[35],tp,tl,cur[35];
bool v[35],used[1100005];

inline void add(int from,int to,int cap){
	l[++t]=(lines){to,0,cap},g[from].pb(t);
	l[++t]=(lines){from,0,0},g[to].pb(t);
}

inline bool BFS(){
	memset(v,0,sizeof(v));
	q[tp=tl=1]=S,v[S]=1,d[S]=0;
	
	int x; lines e;
	while(tp<=tl){
		x=q[tp++];
		for(int i=g[x].size()-1;i>=0;i--){
			e=l[g[x][i]];
			if(e.flow<e.cap&&!v[e.to]){
				v[e.to]=1,d[e.to]=d[x]+1;
				q[++tl]=e.to;
			}
		}
	}
	
	return v[T];
}

int dfs(int x,int A){
	if(x==T||!A) return A;
	
	int flow=0,f,sz=g[x].size();
	for(int &i=cur[x];i<sz;i++){
		lines &e=l[g[x][i]];
		if(d[e.to]==d[x]+1&&(f=dfs(e.to,min(A,e.cap-e.flow)))){
			A-=f,flow+=f;
			e.flow+=f,l[g[x][i]^1].flow-=f;
			if(!A) break;
		}
	}
	
	return flow;
}

inline int max_flow(){
	int an=0;
	while(BFS()){
		memset(cur,0,sizeof(cur));
		an+=dfs(S,1<<30);
	}
	return an;
}

int G[2333],sum[2333],num,zt[1100005];
int Q,n,de[25],cnt,ci[33],HD,val[25];
int hd[445],ne[2333],HF,now,win;

inline bool can(int s){
	int tt=0;
	for(int i=0;i<n;i++) if(ci[i]&s) tt+=ci[val[i]];
	if(used[tt]) return 0;
	used[tt]=1,zt[++num]=tt;

	int OT=0,OM=0,ZT=0,ZM=0;
	for(int i=0;i<n;i++) 
	    if(ci[i]&s) OT++,OM=max(OM,de[i]);
	    else ZT++,ZM=max(ZM,de[i]);
	if(OT<ZM||ZT<OM) return 0;

	S=0,T=n+1,t=-1;
	for(int i=0;i<=T;i++) g[i].clear();
	for(int i=0;i<n;i++)
	    if(ci[i]&s) add(S,i+1,de[i]);
	    else add(i+1,T,de[i]);
	for(int i=0;i<n;i++) if(ci[i]&s)
	    for(int j=0;j<n;j++) if(!(ci[j]&s)) add(i+1,j+1,1);
	
	return max_flow()==HD;
}

inline void front_search(){
	for(int i=0;i<HF;i++) sum[ci[i]]=de[i];
	for(int i=0,N,L;i<ci[HF];i++){
		if(i){
		    N=i&-i,L=N^i;
		    sum[i]=sum[N]+sum[L];
	    }
	    
		G[++cnt]=i,ne[cnt]=hd[sum[i]],hd[sum[i]]=cnt;
	}
}

inline void second_search(){
	for(int i=0;i<n-HF;i++) sum[ci[i]]=de[HF+i];
	for(int i=0,N,L;i<ci[n-HF];i++){
		if(i){
		    N=i&-i,L=N^i;
		    sum[i]=sum[N]+sum[L];
	    }
		
		if(HD-sum[i]>=0){
			N=HD-sum[i];
			int x;
			for(int j=hd[N];j;j=ne[j]){
				x=G[j];
				if(can(x+i*ci[HF])){
					win=1;
					return;
				}
			}
		}
	}
}

inline void solve(int CA){
	for(int i=1;i<=num;i++) used[zt[i]]=0;
	num=cnt=now=win=0,memset(hd,0,sizeof(hd));
	scanf("%d",&n),HF=n>>1,HD=0;
	for(int i=0;i<n;i++) scanf("%d",de+i),HD+=de[i];
	sort(de,de+n),printf("Case %d: ",CA);
	
	val[0]=0;
	for(int i=1;i<n;i++)
	    if(de[i]==de[i-1]) val[i]=val[i-1];
	    else val[i]=i;
	for(int i=0;i<n;i++) now=now*23+de[i];
	
	if(mmp.count(now)){
		if(mmp[now]==1) puts("YES");
		else puts("NO");
		return;
	}
	
	if(HD&1){
		puts("NO");
		return;
	}
	HD>>=1;
	
	front_search();
	second_search();
	
	mmp[now]=win;
	if(win) puts("YES");
	else puts("NO");
}

int main(){
//	freopen("warmap.in","r",stdin);
//	freopen("warmap.out","w",stdout);
	
	ci[0]=1;
	for(int i=1;i<=20;i++) ci[i]=ci[i-1]<<1;
	scanf("%d",&Q);
	for(int i=1;i<=Q;i++) solve(i);
	return 0;
}

  

UVA 12035 War Map