最小树形图简单总结

[BZOJ4349]最小树形图&[BZOJ2260]商店购物

分析?

做法都是先通过最优方案每种选一个,这样最后的答案一定最优。每种选一个的最优方案可以用最小树形图求。

不要忘记写if(e[i].frm!=e[i].to)

第二个题坑点超多,有\(M_i=0\)的情况,据说还有自环。

代码

#include <bits/stdc++.h>
#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;

inline int read(){
	int 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 x*f;
}

inline double readd(){
	double x;scanf("%lf",&x);return x;
}

const int MAXN=55;
const double eps=1e-8;
int n,m,s,ecnt,head[MAXN],b[MAXN],id[MAXN];
int	pre[MAXN],vis[MAXN],blg[MAXN];
double a[MAXN],minw[MAXN],ans;
bool ban[MAXN];
struct Edge{int frm,to,nxt;double w;}e[MAXN*MAXN+MAXN];

inline void add_edge(int bg,int ed,double val){
	ecnt++;e[ecnt].frm=bg;e[ecnt].to=ed;e[ecnt].nxt=head[bg];e[ecnt].w=val;head[bg]=ecnt;
}

void zhuliu(){
	while(1){
		memset(minw,0x43,sizeof minw);memset(pre,0,sizeof pre);memset(vis,0,sizeof vis);memset(blg,0,sizeof blg);
		rin(i,1,ecnt) if(e[i].frm!=e[i].to) if(e[i].w<minw[e[i].to]) minw[e[i].to]=e[i].w,pre[e[i].to]=e[i].frm;
		bool flag=false;
		minw[s]=0,pre[s]=0;
		rin(i,1,s) if(!ban[i]){
			ans+=minw[i];int now=i;
			while(now&&!vis[now]) vis[now]=i,now=pre[now];
			if(vis[now]==i){
				flag=true;blg[now]=now;int temp=now;now=pre[now];
				while(now!=temp) blg[now]=temp,now=pre[now];
			}
		}
		if(!flag) return;
		rin(i,1,s) if(!ban[i]&&!blg[i]) blg[i]=i; else if(!ban[i]&&blg[i]!=i) ban[i]=true;
		rin(i,1,ecnt) if(e[i].frm!=e[i].to) e[i].w-=minw[e[i].to],e[i].frm=blg[e[i].frm],e[i].to=blg[e[i].to];
	}
}

int main(){
	n=read();int temp=0;
	rin(i,1,n){
		a[i]=readd(),b[i]=read(),++temp;
		if(!b[i]){n--,i--;continue;}id[temp]=i;
	}
	s=n+1;
	rin(i,1,n) add_edge(s,i,a[i]);
	m=read();
	rin(i,1,m){
		int x=id[read()],y=id[read()];double z=readd();
		if(!x||!y) continue;if(x!=y) add_edge(x,y,z);a[y]=std::min(a[y],z);
	}
	zhuliu();
	rin(i,1,n) ans+=(b[i]-1)*a[i];
	printf("%.2f\n",ans+eps);
	return 0;
}

posted on 2019-01-18 10:06  ErkkiErkko  阅读(174)  评论(0编辑  收藏

统计