【Codeforces】512C Fox and Dinner

【解析】歐拉篩法,奇偶分析,建二分圖,網絡流

[Analysis]

http://blog.csdn.net/qq574857122/article/details/43453087。

所謂的連通塊就是指滿流了,由於我直接使用剩餘流量求網絡流。
至於如何判斷滿流,我想到以下幾種:
①對於初始的網絡,若圖的流向是一樣的,那麼就直接判斷對於一條邊k的正向邊k>>1<<1是否滿流。
②對於一般的,可以存流量限制。
③或者對每條邊再存個tag,若tag=1,則表示初始時這條邊容量限制非0,否則是0。

[Q&A]
問題1:爲什麼這樣搜索可以出解而不錯誤?
回答1:這不是很明顯的嘛,由於滿流了,所以除原點和匯點外的每個節點連接且僅連接兩個節點。
這樣從一個節點過來,那麼必然只能從另一個節點出去。
最後必然會有一個節點連接到第一個節點,這是就停止了,假如沒有,那麼一直找到了第n個節點就找不到了,矛盾。
特殊的,對於每個連通集合的第一個節點,選擇了任意一個相鄰的節點,這也是沒問題的。

[Sum]
①對於素數的問題,要想到奇偶分析。
②k!=-1,等價於~k,這裏可以化簡,其實scanf("%d",&a)這個函數如果讀不到任何東西,返回的值也是-1。
之所以能這樣因爲-1的二進制爲最大即2^k-1,取反後爲0,而其他取反都非0。
③判斷滿流的三種辦法。
④回顧了網絡流算法。

[Code]
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

const int N=240;
const int M=N*N;
const int P=20001;

int n,odd[N],even[N];
int w[N],pri[P],vp[P];
struct G
{
	int v,f,nxt;
}map[M+M];
int tt,hd[N];
int level[N],q[N],h,t;
G list[N]; int tl,used[N],fs[N],num,cnt[N];

inline int read(void)
{
	int s=0; char c=getchar();
	for (;c<'0'||c>'9';c=getchar());
	for (;'0'<=c&&c<='9';c=getchar()) s=s*10+c-'0';
	return s;
}

inline void ins(int u,int v,int f)
{
	map[++tt].v=v;
	map[tt].f=f;
	map[tt].nxt=hd[u];
	hd[u]=tt;
}

int init(void)
{
	n=read();

	for (int i=1;i<=n;i++)
	{
		w[i]=read();
		if (w[i]&1) 
			odd[++odd[0]]=i;
		else even[++even[0]]=i;
	}
	if (odd[0]^even[0]) return 0;

	for (int i=2;i<P;i++)
	{
		if (!vp[i]) pri[++pri[0]]=i;
		for (int j=1;j<=pri[0];j++)
		{
			if (i*pri[j]>=P) break;
			vp[i*pri[j]]=1;
			if (i%pri[j]==0) break;
		}
	}
	
	tt=-1; memset(hd,-1,sizeof hd);
	for (int i=1;i<=odd[0];i++)
	{
		ins(0,odd[i],2),ins(odd[i],0,0);
		for (int j=1;j<=even[0];j++)
			if (!vp[w[odd[i]]+w[even[j]]])
				ins(odd[i],even[j],1),ins(even[j],odd[i],0);
	}
	for (int i=1;i<=even[0];i++)
		ins(even[i],n+1,2),ins(n+1,even[i],0);
	
	return 1;
}

int BFS(void)
{
	memset(level,-1,sizeof level);
	h=0,t=1,q[t]=0,level[0]=0;
	
	int k;
	for (;h^t;)
	{
		k=q[++h];
		for (int r=hd[k];~r;r=map[r].nxt)
			if (map[r].f&&level[map[r].v]==-1)
			{
				level[map[r].v]=level[k]+1;
				if (map[r].v==n+1) return 1;
				q[++t]=map[r].v;
			}
	}
	return 0;
}

inline int min(int i,int j)
{
	return i<j?i:j;
}

int DFS(int now,int flow)
{
	if (now==n+1) return flow;
	int sum=0,tmp;
	for (int k=hd[now];~k;k=map[k].nxt)
		if (map[k].f&&level[now]+1==level[map[k].v])
		{
			tmp=DFS(map[k].v,min(flow,map[k].f));
			if (tmp)
			{
				map[k].f-=tmp;
				map[k^1].f+=tmp;
				flow-=tmp;
				sum+=tmp;
				if (!flow) break;
			}
			else level[map[k].v]=P;
		}
	return sum;
}

inline void inslist(int now)
{
	list[++tl].v=now;
	list[tl].nxt=fs[num];
	fs[num]=tl;
}

void dfs(int now,int fst)
{
	cnt[num]++;
	used[now]=1;
	inslist(now);
	
	for (int k=hd[now];k;k=map[k].nxt)
		if (!map[k>>1<<1].f&&map[k].v&&map[k].v^n+1)
		{
			if (fst==map[k].v) return;
			if (!used[map[k].v]) dfs(map[k].v,fst);
		}
}

int work(void)
{
	int sum=0;
	for (;BFS();) sum+=DFS(0,P);
	if (sum^n) return 0;
	
	for (int i=1;i<=n;i++)
		if (!used[i])
		{
			num++;
			dfs(i,i);
		}
	
	printf("%d\n",num);
	for (int i=1;i<=num;i++)
	{
		printf("%d ",cnt[i]);
		for (int j=fs[i];j;j=list[j].nxt)
			printf("%d ",list[j].v);
		printf("\n");
	}
	
	return 1;
}

int main(void)
{	
	int d=init();
	if (d) d=work();
	if (!d) printf("Impossible\n");
	
	return 0;
}

發佈了137 篇原創文章 · 獲贊 4 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章