题解 旅行

传送门

限制里的「每对互相关联的边都是共起点的」很奇特
于是发现每个点间都是互相独立的,考虑维护 \(dp_i\) 表示节点 \(i\) 向下的最大收益
于是发现 \(dp_i=\frac{\sum dp_v\times w_i}{\sum w_i},\ w_i\in\{0, 1\}\)
于是可以用01分数规划做
考虑如何check
发现关联都形如「若不选择 \(y\),则不选择 \(x\)
所以「若选择 \(x\),一定选择 \(y\)
就变成了最大闭合子图的形式了
注意要开long double不然会炸

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define fir first
#define sec second
#define pb push_back
#define double long double
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, k;
bool vis[N];
int head[N], cnt[N], ord[N], num, size;
vector<int> link[N], cause[N];
double ans;
struct edge{int to, next; bool del;}e[N<<1];
inline void add(int s, int t) {e[++size]={t, head[s]}; head[s]=size;}

namespace force{
	int q[N], ql, qr;
	int cnt2[N];
	double dp[N];
	double calc() {
		for (int i=1; i<=n; ++i) dp[i]=0;
		for (int i=num; i; --i) {
			int u=ord[i], deg=0;
			for (int i=head[u],v; ~i; i=e[i].next) if (!e[i].del) {
				v = e[i].to;
				++deg;
				dp[u]+=(dp[v]+1);
			}
			if (deg) dp[u]/=deg;
		}
		// cout<<"dp: "; for (int i=1; i<=n; ++i) cout<<dp[i]<<' '; cout<<endl;
		return dp[1];
	}
	void solve() {
		int lim=1<<m;
		ql=1, qr=0;
		for (int i=1; i<=n; ++i) {
			if (!cnt[i]) q[++qr]=i;
			cnt2[i]=cnt[i];
		}
		while (ql<=qr) {
			int u=q[ql++];
			ord[++num]=u;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (--cnt2[v]==0) q[++qr]=v;
			}
		}
		// cout<<"ord: "; for (int i=1; i<=num; ++i) cout<<ord[i]<<' '; cout<<endl;
		for (int s=0; s<lim; ++s) {
			ql=1, qr=0;
			for (int i=1; i<=m; ++i) vis[i]=0;
			for (int i=0; i<m; ++i) if (s&(1<<i)) {
				q[++qr]=i+1; vis[i+1]=1;
			}
			while (ql<=qr) {
				int u=q[ql++];
				for (auto it:link[u]) if (!vis[it]) q[++qr]=it, vis[it]=1;
			}
			for (int i=1; i<=m; ++i)
				if (vis[i]) e[i].del=1;
				else e[i].del=0;
			ans=max(ans, calc());
		}
		printf("%.6lf\n", ans);
		exit(0);
	}
}

namespace task{
	int top, s, t;
	double dp[N];
	pair<int, double> sta[N];
	queue<int> q;
	namespace dinic{
		const double eps=1e-3;
		int head[5100], size, cur[5100], dep[5100];
		struct edge{int to, next; double val;}e[N<<1];
		inline void add(int s, int t, double w) {e[++size]={t, head[s], w}; head[s]=size;}
		void init() {size=1; memset(head, -1, sizeof(head));}
		bool bfs(int s, int t) {
			memset(dep, 0, sizeof(dep));
			queue<int> q;
			dep[s]=1; cur[s]=head[s];
			q.push(s);
			int u;
			while (q.size()) {
				u=q.front(); q.pop();
				for (int i=head[u],v; ~i; i=e[i].next) {
					v = e[i].to;
					if (fabs(e[i].val)>eps&&!dep[v]) {
						dep[v]=dep[u]+1;
						cur[v]=head[v];
						if (v==t) return 1;
						q.push(v);
					}
				}
			}
			return 0;
		}
		double dfs(int u, double in) {
			if (u==t||!in) return in;
			double rest=in, tem;
			for (int i=cur[u],v; ~i; cur[u]=i=e[i].next) {
				v = e[i].to;
				if (fabs(e[i].val)>eps&&dep[v]==dep[u]+1) {
					tem=dfs(v, min(rest, e[i].val));
					if (!tem) dep[v]=0;
					rest-=tem;
					e[i].val-=tem;
					e[i^1].val+=tem;
					if (!rest) break;
				}
			}
			return in-rest;
		}
		double dinic() {
			double ans=0;
			while (bfs(s, t)) ans+=dfs(s, INF);
			return ans;
		}
	}
	void solve() {
		s=m+1; t=m+2;
		for (int i=1; i<=n; ++i) if (!cnt[i]) q.push(i);
		int u;
		while (q.size()) {
			u=q.front(); q.pop();
			ord[++num]=u;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (--cnt[v]==0) q.push(v);
			}
		}
		// cout<<"ord: "; for (int i=1; i<=num; ++i) cout<<ord[i]<<' '; cout<<endl;
		for (int i=num; i; --i) {
			// cout<<"i: "<<i<<' '<<ord[i]<<endl;
			if (head[ord[i]]==-1) {dp[ord[i]]=0; continue;}
			top=0;
			for (int j=head[ord[i]]; ~j; j=e[j].next) sta[++top]={j, dp[e[j].to]+1};
			// sta[2].sec=2;
			// cout<<"sta: "; for (int j=1; j<=top; ++j) cout<<sta[j].fir<<','<<sta[j].sec<<' '; cout<<endl;
			double l=0, r=500, mid;
			for (int j=1; j<=40; ++j) {
				double ans=0;
				mid=(l+r)/2;
				// mid=1.95312;
				// printf("check: %.8lf\n", mid);
				dinic::init();
				for (int k=1; k<=top; ++k) {
					if (sta[k].sec-mid>0) dinic::add(s, sta[k].fir, sta[k].sec-mid), dinic::add(sta[k].fir, s, 0), ans+=sta[k].sec-mid; //, cout<<"add: "<<s<<' '<<sta[k].fir<<endl;
					else dinic::add(sta[k].fir, t, mid-sta[k].sec), dinic::add(t, sta[k].fir, 0); //, cout<<"add: "<<sta[k].fir<<' '<<t<<endl;
					if (cause[sta[k].fir].size()) for (auto it:cause[sta[k].fir]) dinic::add(sta[k].fir, it, INF), dinic::add(it, sta[k].fir, 0); //, cout<<"add: "<<sta[k].fir<<' '<<it<<endl; //, cout<<"it: "<<it<<endl;
				}
				// cout<<"dinic: "<<dinic::dinic()<<endl;
				// printf("ans: %.10lf\n", ans);
				double t;
				if (ans-(t=dinic::dinic())>0.999e-7) l=mid; //, cout<<"return 1"<<endl; //, cout<<"pos1"<<endl;
				else r=mid; //, cout<<"return 2"<<endl; //, cout<<"pos2"<<endl;
				// printf("t: %.10lf\n", t);
			}
			dp[ord[i]]=l;
			// printf("%.15lf\n", dp[ord[i]]);
		}
		printf("%.10Lf\n", dp[1]);
		exit(0);
	}
}

signed main()
{
	n=read(); m=read(); k=read();
	memset(head, -1, sizeof(head));
	for (int i=1,u,v; i<=m; ++i) {
		u=read(); v=read();
		add(u, v);
		++cnt[v];
	}
	for (int i=1,x,y; i<=k; ++i) {
		x=read(); y=read();
		link[y].pb(x); cause[x].pb(y);
	}
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2021-12-26 21:11  Administrator-09  阅读(0)  评论(0编辑  收藏  举报