卧薪尝胆,厚积薄发。
跨平面
Date: Sun Dec 16 16:29:52 CST 2018 In Category: NoCategory

Description:

给一个平面图,从一个区域到另一个区域两个方向有不同的花费,问用最小的代价和使得从某个点出发可以到达其他所有点。
$1\leqslant n\leqslant 3010,1\leqslant m\leqslant 10000$

Solution:

先用最小左转法找出所有的平面,然后建出对偶图,然后在对偶图上跑一个朱刘算法即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<set>
#include<cctype>
#include<cstring>
using namespace std;
#define MAXN 3010
#define MAXM 10010
int n,m;
#define INF 0x3f3f3f3f
namespace MST
{
int pn;
struct edge
{
int fr,to,w;
}e[MAXM];
int edgenum = 0;
void add(int a,int b,int w)
{
e[++edgenum] = (edge){a,b,w};
return;
}
int vis[MAXN];
int id[MAXN];
int in[MAXN],pre[MAXN];
int root;
int solve()
{
int ans = 0;
while(true)
{
memset(vis,0,sizeof(vis));
memset(id,0,sizeof(id));
memset(in,0x3f,sizeof(in));
for(int i = 1;i <= edgenum;++i)
{
if(e[i].fr != e[i].to && e[i].w < in[e[i].to])
{
in[e[i].to] = e[i].w;
pre[e[i].to] = e[i].fr;
}
}
in[root] = 0;
int cnt = 0;
for(int i = 1;i <= pn;++i)
{
if(in[i] == INF)return -1;
ans += in[i];
int k;
for(k = i;k != root && id[k] == 0 && vis[k] != i;k = pre[k])vis[k] = i;
if(k != root && id[k] == 0)
{
id[k] = ++cnt;
for(int j = pre[k];j != k;j = pre[j])id[j] = cnt;
}
}
if(cnt == 0)return ans;
for(int i = 1;i <= pn;++i)if(id[i] == 0)id[i] = ++cnt;
for(int i = 1;i <= edgenum;++i)
{
int tag = in[e[i].to];
e[i].fr = id[e[i].fr];
e[i].to = id[e[i].to];
if(e[i].fr != e[i].to)e[i].w -= tag;
}
root = id[root];
pn = cnt;
}
}
}
struct point
{
int x,y;
}p[MAXN];
point operator - (point a,point b){return (point){a.x - b.x,a.y - b.y};}
double angle(point k){return atan2(k.y,k.x);}
long long operator * (point a,point b){return 1ll * a.x * b.y - 1ll * a.y * b.x;}
struct vector
{
int x,y,val;
double k;
}v[MAXM << 1];
int vnum = 0;
void add(int a,int b,int val)
{
v[vnum++] = (vector){a,b,val,angle(p[b] - p[a])};
return;
}
bool vis[MAXM << 1];
int belong[MAXM << 1];
int tot = 0;
int stack[MAXM << 1],top = 0;
struct cmp
{
bool operator ()(int a,int b){return v[a].k < v[b].k;}
};
set<int,cmp> s[MAXN];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)scanf("%d%d",&p[i].x,&p[i].y);
int a,b,v1,v2;
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d%d",&a,&b,&v1,&v2);
add(a,b,v1);add(b,a,v2);
}
for(int i = 0;i < 2 * m;++i)
{
s[v[i].x].insert(i);
}
for(int i = 0;i < 2 * m;++i)
{
if(vis[i])continue;
stack[top = 1] = i;vis[i] = true;
long long sum = 0;
while(true)
{
set<int,cmp>::iterator it = s[v[stack[top]].y].find(stack[top] ^ 1);
++it;
if(it == s[v[stack[top]].y].end())it = s[v[stack[top]].y].begin();
if(*it == i)break;
stack[++top] = *it;
vis[stack[top]] = true;
}
for(int j = 1;j <= top;++j)
{
sum += p[v[stack[j]].x] * p[v[stack[j]].y];
}
++tot;
while(top)belong[stack[top--]] = tot;
}
for(int i = 0;i < 2 * m;++i)
{
if(v[i].val != 0)MST::add(belong[i ^ 1],belong[i],v[i].val);
}
MST::pn = tot + 1;
MST::root = tot + 1;
for(int i = 1;i <= tot;++i)MST::add(tot + 1,i,100000);
cout << MST::solve() - 100000 << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡