ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【日常训练】20200304_T3_栅栏fence_平面图转对偶图/最小割树_HDU5518

2021-03-04 23:02:43  阅读:221  来源: 互联网

标签:10 HDU5518 cn cm 20200304 int pos G1 fence


题面

给一张平面图,每条边有权值,一个环的权值为其每条边的权值和,求一个权值最小的环的集合使得所有环都能通过这个集合中的环异或得到。

题解

现场得分:30/30

这道题有点难写,因为我当时写了一个平面图转对偶图,还有一个特殊线性基。很长。不过竟然调对了。

  • 先平面图转对偶图,定好方向转转转就好了。然后我们在原图中希望用环权和尽可能小的环把每种环都异或出来。

  • 这意味着我们对于原图中的任意两个基本的环(即转转转转出来的那些),我们希望用一个代价最小的环来将其区分开来。原图中的环对应对偶图中的最小割。所以我们现在希望在新图中用尽可能小的割来将所有点分开来。

  • 跑最小割树。最小割树边权和为答案。

  • 但是,说实在的,我上面写了三句话,我并不能很好地解释每句话之间是如何推导的,甚至有点怀疑。

代码

#include<bits/stdc++.h>
#define LL long long
#define U unsigned
#define eps 0.000001
#define MAXN 1010
#define INF 1000000000
using namespace std;
template<typename T> void Read(T &cn)
{
	char c; int sig = 1;
	while(!isdigit(c = getchar())) if(c == '-') sig = 0;
	if(sig) {cn = c-48; while(isdigit(c = getchar())) cn = cn*10-48+c; }
	else    {cn = 48-c; while(isdigit(c = getchar())) cn = cn*10+48-c; }
}
template<typename T> void Write(T cn)
{
	T cm = 0; int wei = 0, cx = cn%10; cn = cn/10;
	if(cn < 0 || cx < 0) {putchar('-'); cn = -cn; cx = -cx; }
	while(cn) wei++, cm = cm*10+cn%10, cn = cn/10;
	while(wei--) putchar(cm%10+48), cm = cm/10;
	putchar(cx+48);
}
template<typename T> void WriteL(T cn) {Write(cn); puts(""); }
template<typename T> void WriteS(T cn) {Write(cn); putchar(' '); }
template<typename T> void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; }
template<typename T> void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
struct Point{
	double x, y;
	void getit() {scanf("%lf %lf",&x,&y); }
	void mk(double cn, double cm) {x = cn; y = cm; }
	inline friend bool operator <(Point cn, Point cm) {return fabs(cn.x-cm.x)<=eps ? (fabs(cn.y-cm.y)<=eps ? 0 : cn.y < cm.y) : cn.x < cm.x; }
	inline friend Point operator -(Point cn, Point cm) {Point guo; guo.mk(cn.x-cm.x,cn.y-cm.y); return guo; }
};
struct Graph{
	struct qwe{
		int a,b,ne,yong,w;
		void mk(int cn, int cm, int cx, int cw) {a = cn; b = cm; ne = cx; w = cw; yong = 0; }
	};
	qwe a[MAXN*2+1];
	int alen;
	int head[MAXN+1];
	void lian(int cn, int cm, int cx) {a[++alen].mk(cn,cm,head[cn],cx); head[cn] = alen; }
	void liand(int cn, int cm, int cx) {lian(cn,cm,cx); lian(cm,cn,cx); }
	void build() {alen = 0; memset(head,0,sizeof(head)); }
};
struct Paixu{
	Point pos;
	int wei;
	void mk(Point cn, int cm) {pos = cn; wei = cm; }
};
double chaji(Point cn, Point cm) {return cn.x*cm.y-cm.x*cn.y; }
map<Point, int> M;
Point pos[MAXN+1];
int m, n1, n2, t;
Graph G1, G2;
int zhan[MAXN+1], zlen;
int ne[MAXN+1][MAXN+1], nelen[MAXN+1];
Paixu zhan2[MAXN+1];
int val[MAXN+1];
int get_Poi() {Point cn; cn.getit(); if(M.find(cn) == M.end()) M[cn] = ++n1, pos[n1] = cn; return M[cn]; }
int Cmp(Paixu cn, Paixu cm) 
{
	if(cn.wei == cm.wei) return 0;
	if(cn.pos.x == 0 && cn.pos.y<0) return 1;
	if(cm.pos.x == 0 && cm.pos.y<0) return 0;
	if(cn.pos.x == 0) return cm.pos.x < 0;
	if(cm.pos.x == 0) return cn.pos.x > 0;
	if(cn.pos.x > 0 && cm.pos.x < 0) return 1;
	if(cn.pos.x < 0 && cm.pos.x > 0) return 0;
	return chaji(cn.pos,cm.pos) > 0;
}
namespace Sub1{
	int pan() {return n2 >= 25 ? 0 : ((1<<n2)*G2.alen <= 40000000); }
	struct Jihe{
		int S, he;
		void mk(int cn, int cm) {S = cn; he = cm; }
		inline friend bool operator <(Jihe cn, Jihe cm) {return cn.he == cm.he ? cn.S < cm.S : cn.he < cm.he; }
	};
	struct Xxj{
		Jihe a[100];
		int n;
		LL he;
		void build(int cn) {n = cn; for(int i = 0;i<n;i++) a[i].mk(0,0); he = 0; }
		void cha(int cn, int cm)
		{
			for(int i = n-1;i>=0;i--) if(cn&(1<<i))
			{
				if(!a[i].S) {a[i].mk(cn, cm); he = he+cm; return; }
				cn = cn ^ a[i].S;
			}
		}
	}xxj;
	Jihe zhan[MAXN+1];
	int zlen;
	int fa[MAXN+1], you[MAXN+1];
	int get_fa(int cn) {return fa[cn] == cn ? cn : fa[cn] = get_fa(fa[cn]); }
	int main()
	{
		zlen = 0;
		for(int i = 1;i<(1<<n2);i++) 
		{
			for(int j = 1;j<=n2;j++) you[j] = (i&(1<<(j-1)))!=0;
			for(int j = 1;j<=n2;j++) fa[j] = j;
			int zong = 0;
			for(int j = 1;j<=n2;j++) if(you[j])
			{
				zong++;
				for(int ij = G2.head[j];ij;ij = G2.a[ij].ne) if(you[G2.a[ij].b] && get_fa(G2.a[ij].b) != get_fa(j))
				{
					zong--; fa[get_fa(G2.a[ij].b)] = get_fa(j);
				}
			}
			if(zong != 1) continue;
//			printf("i = %d\n",i);
//			for(int j = 1;j<=n2;j++) printf("you[%d] = %d\n",j,you[j]);
			LL lei = 0;
			for(int j = 1;j<=n2;j++) if(you[j])
			{
				for(int ij = G2.head[j];ij;ij = G2.a[ij].ne) if(you[G2.a[ij].b]) lei = lei + G2.a[ij].w;
			}
//			printf("lei = %lld\n",lei);
			lei = -lei;
			for(int j = 1;j<=n2;j++) if(you[j]) lei = lei + val[j];
//			printf("lei = %lld\n",lei);
			zhan[++zlen].mk(i, lei);
		}
		sort(zhan+1, zhan+zlen+1);
		xxj.build(n2);
		for(int i = 1;i<=zlen;i++) xxj.cha(zhan[i].S, zhan[i].he);
		WriteL(xxj.he);
		return 0;
	}
}
namespace Sub2{
	Graph G;
	struct Flow{
		int shen[MAXN+1], lst[MAXN+1], dui[MAXN+1];
		LL ans;
		int bfs(int cn, int cm, int ctot)
		{
			for(int i = 1;i<=ctot;i++) shen[i] = ctot+1, lst[i] = G2.head[i];
			int l = 0, r = 0; dui[++r] = cn; shen[cn] = 0;
			while(l < r)
			{
				int dang = dui[++l];
				for(int i = G2.head[dang];i;i = G2.a[i].ne)
				{
					int y = G2.a[i].b;
					if(G2.a[i].w == 0 || shen[y] <= shen[dang]+1) continue;
					shen[y] = shen[dang]+1; dui[++r] = y;
				}
			}
			return shen[cm] != ctot+1;
		}
		int dfs(int cn, int cm, int liu)
		{
			if(cn == cm) {ans = ans + liu; return liu; }
			for(int &i = lst[cn];i;i = G2.a[i].ne)
			{
				int y = G2.a[i].b;
				if(G2.a[i].w == 0 || shen[y] != shen[cn]+1) continue;
				int lin = dfs(y, cm, min(liu, G2.a[i].w));
				if(lin) {
					G2.a[i].w -= lin; G2.a[((i-1)^1)+1].w += lin; return lin;
				}
			}
			return 0;
		}
		void sou_fen(int cn, int fen[])
		{
			if(fen[cn]) return; fen[cn] = 1;
			for(int i = G2.head[cn];i;i = G2.a[i].ne) if(G2.a[i].w) sou_fen(G2.a[i].b, fen);
		}
		LL flow(int cn, int cm, int ctot, int fen[])
		{
			ans = 0;
			while(bfs(cn,cm,ctot)) while(dfs(cn,cm,INF));
			for(int i = 1;i<=ctot;i++) fen[i] = 0;
			sou_fen(cn, fen);
			return ans;
		}
	}W;
	int zhan[MAXN+1], zhan2[MAXN+1], zlen;
	int fen[MAXN+1];
	LL ans;
	void sou(int cl, int cr)
	{
//		printf("in sou : cl = %d cr = %d\n",cl,cr);
		if(cl == cr) return;
		for(int i = 1;i<=G2.alen;i++) G.a[i].w = G2.a[i].w;
		int lin = W.flow(zhan[cl], zhan[cr], n2, fen);
		for(int i = 1;i<=G2.alen;i++) G2.a[i].w = G.a[i].w;
		ans = ans + lin;
//		printf("lin = %d\n",lin);
//		for(int i = 1;i<=n2;i++) printf("fen[%d] = %d\n",i,fen[i]);
		zlen = 0; for(int i = cl;i<=cr;i++) if(fen[zhan[i]]) zhan2[++zlen] = zhan[i];
		int geshu = cl+zlen-1;
		for(int i = cl;i<=cr;i++) if(!fen[zhan[i]]) zhan2[++zlen] = zhan[i];
		for(int i = cl;i<=cr;i++) zhan[i] = zhan2[i-cl+1];
		sou(cl, geshu); sou(geshu+1, cr);
	}
	int main()
	{
		for(int i = 1;i<=n2;i++) zhan[i] = i; ans = 0;
		sou(1, n2);
		WriteL(ans);
		return 0;
	}
}
int zuo()
{
	Read(m);
	M.clear(); G1.build(); G2.build();
	n1 = n2 = 0;
	for(int i = 1;i<=m;i++)
	{
		int bx = get_Poi(), by = get_Poi();
		int bz; Read(bz); 
		G1.liand(bx,by,bz);
	}
//	for(int i = 1;i<=n1;i++) printf("%d : (%.0lf %.0lf)\n",i,pos[i].x,pos[i].y);
//	for(int i = 1;i<=G1.alen;i++) printf("G1 : %d : (%d -> %d) %d\n",i,G1.a[i].a,G1.a[i].b,G1.a[i].w);
	for(int i = 1;i<=n1;i++)
	{
		nelen[i] = 0;
		for(int j = G1.head[i];j;j = G1.a[j].ne) zhan2[++nelen[i]].mk(pos[G1.a[j].b]-pos[i], j);
		sort(zhan2+1, zhan2+nelen[i]+1, Cmp);
		for(int j = 1;j<=nelen[i];j++) ne[i][j] = zhan2[j].wei;
//		for(int j = 1;j<=nelen[i];j++) printf("ne[%d][%d] = %d\n",i,j,ne[i][j]);
	}
	for(int i = 1;i<=G1.alen;i++) if(!G1.a[i].yong)
	{
//		printf("i = %d (%d, %d)\n",i,G1.a[i].a,G1.a[i].b);
		zlen = 0; int xian = G1.a[i].b, lst = G1.a[i].a;
		zhan[++zlen] = i;
		while(xian != G1.a[i].a) 
		{
			int nxt = 0;
			for(int j = 1;j<=nelen[xian];j++) if(G1.a[ne[xian][j]].b == lst) nxt = j;
			if(nxt == 1) nxt = ne[xian][nelen[xian]];
			else nxt = ne[xian][nxt-1];
			zhan[++zlen] = nxt; lst = xian; xian = G1.a[nxt].b;
		}
		double he = 0;
		Point yuan = pos[G1.a[zhan[1]].a];
		for(int j = 1;j<=zlen;j++) he = he + chaji(pos[G1.a[zhan[j]].a]-yuan, pos[G1.a[zhan[j]].b]-yuan);
//		for(int j = 1;j<=zlen;j++) printf("zhan[%d] = %d (%d->%d)\n",j,zhan[j],G1.a[zhan[j]].a,G1.a[zhan[j]].b);
		if(he < 0) for(int j = 1;j<=zlen;j++) G1.a[zhan[j]].yong = -1;
		else {
			n2++; val[n2] = 0; 
			for(int j = 1;j<=zlen;j++) G1.a[zhan[j]].yong = n2, val[n2] += G1.a[zhan[j]].w;
		}
	}
	n2++; val[n2] = 0;
	for(int i = 1;i<=G1.alen;i++) if(G1.a[i].yong == -1) G1.a[i].yong = n2;
	for(int i = 1;i<=G1.alen;i+=2) if(G1.a[i].yong > 0 && G1.a[i+1].yong > 0) G2.liand(G1.a[i].yong, G1.a[i+1].yong, G1.a[i].w);
//	for(int i = 1;i<=G2.alen;i++) printf("G2 : %d : (%d -> %d) %d\n",i,G2.a[i].a,G2.a[i].b,G2.a[i].w);
//	for(int i = 1;i<=n2;i++) printf("val[%d] = %d\n",i,val[i]);
//	if(Sub1::pan()) return Sub1::main();
	return Sub2::main();
}
signed main()
{
	freopen("fence.in","r",stdin);
	freopen("fence.out","w",stdout);
	Read(t); for(int i = 1;i<=t;i++) printf("Case #%d: ",i), zuo();
	return 0;
}
/*
2
5
0 0 0 1 1
0 0 1 0 1
0 1 1 1 1
1 0 1 1 1
1 0 0 1 100
9
1 1 3 1 1
1 1 1 3 2
3 1 3 3 2
1 3 3 3 1
1 1 2 2 2
2 2 3 3 3
3 1 2 2 1
2 2 1 3 2
4 1 5 1 4

1
12
1 1 2 1 1
1 1 2 2 2
1 1 2 3 1
2 1 2 2 1
2 2 2 3 1
2 1 3 1 1
2 1 3 2 1
2 2 3 2 1
2 3 3 2 1
2 3 3 3 1
3 1 3 2 1
3 2 3 3 1
*/

标签:10,HDU5518,cn,cm,20200304,int,pos,G1,fence
来源: https://www.cnblogs.com/czyarl/p/14483555.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有