在洛谷,拿到了9分、18分、82分、91分都分别是因为什么呢?在后文中有详细的解释。
题目链接
刚看到这道题的时候,我第一反应就是一道将每个区间的价值变换的最长k可重区间集问题【网络流24题】【最大流最小费用】这道题,但是,按照这个写法,T了,9分……
为什么会T呢?我开始去想这个问题,对!存在负环!那么改,我把每个点都去拆点,然后限制流过每个点的流量为K,这样子就可以去保证最大K重叠的问题了,但是WA了,18分……
怎么解决WA的问题呢?我想了下会不会是最后的答案上爆了精度!(又让我想起电子科大的校赛被卡了这题),改了精度,91分!!!震惊了,还真是被卡了精度啊。
那么还有一组样例过不去啊,怎么办呢?然后开始拼命的改了,我控制输出流,也就是流出的流量一定要恒≤K,然后再去跑最大流的最小费用(边为负边权),如何去考虑这个流过的流量限流呢?看到一种很不错的方法,就是对于每个节点的左右区间(我强制令左端点<右端点),那么,接下去,对于左右端点,我们让他们都扩大到自己的两倍,并且,左端点再加上1,如果原本的左右端点相等的话,就会让左端点>右端点,所以要去改变,但是为什么不是去更改大的端点呢?是有原因的。举个例子,(5, 5)和(5, 7),因为(5, 7)这个点是不会经过"5"的,但是我们得对5限流,所以如果同样是从5出发的话会导致5的流出过小了,所以得改!
改完之后,82分???还T了两组,什么情况?然后突然发现,自己竟然没有加上那个判断左右端点大小的那个判断,如此就会形成死循环了,改完,A了。呼~
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define esp 1e-6
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 2e3 + 7, maxE = 3e4 + 7, S = 0;
int N, K, head[maxN], cnt, a[507][2], lsan[maxN], T, diff, num[maxN];
ll val[507];
struct Eddge
{
int nex, u, v, flow;
ll cost;
Eddge(int a=-1, int b=0, int c=0, int d=0, ll f=0):nex(a), u(b), v(c), flow(d), cost(f) {}
}edge[maxE];
inline void addEddge(int u, int v, int flow, ll cost)
{
edge[cnt] = Eddge(head[u], u, v, flow, cost);
head[u] = cnt++;
}
inline void _add(int u, int v, int flow, ll cost) { addEddge(u, v, flow, cost); addEddge(v, u, 0, -cost); }
int Flow[maxN], pre[maxN];
ll dist[maxN];
bool inque[maxN];
queue<int> Q;
bool spfa()
{
memset(pre, -1, sizeof(pre)); memset(dist, INF, sizeof(dist)); memset(inque, false, sizeof(inque));
while(!Q.empty()) Q.pop();
Q.push(S); inque[S] = true; Flow[S] = INF; dist[S] = 0;
while(!Q.empty())
{
int u = Q.front(); inque[u] = false; Q.pop();
for(int i=head[u], v, f; ~i; i=edge[i].nex)
{
v = edge[i].v; f = edge[i].flow; ll c = edge[i].cost;
if(f && dist[v] > dist[u] + c)
{
dist[v] = dist[u] + c;
Flow[v] = min(Flow[u], f);
pre[v] = i;
if(!inque[v])
{
inque[v] = true;
Q.push(v);
}
}
}
}
return pre[T] ^ -1;
}
ll EK()
{
ll ans = 0;
while(spfa())
{
int now = T, las = pre[now];
while(now)
{
edge[las].flow -= Flow[T];
edge[las ^ 1].flow += Flow[T];
now = edge[las].u;
las = pre[now];
}
ans += (ll)dist[T] * Flow[T];
}
return -ans;
}
inline void init()
{
cnt = 0;
memset(head, -1, sizeof(head)); memset(num, 0, sizeof(num));
}
int main()
{
scanf("%d%d", &N, &K);
init();
for(int i=1, y1, y2; i<=N; i++)
{
scanf("%d%d%d%d", &a[i][0], &y1, &a[i][1], &y2);
val[i] = (int)sqrt( (ll)(a[i][0] - a[i][1]) * (ll)(a[i][0] - a[i][1]) + (ll)(y1 - y2) * (ll)(y1 - y2) + esp);
if(a[i][1] < a[i][0]) swap(a[i][0], a[i][1]); //这里是为了保证左右区间的区间是正确的,保证左<右(不过去除了这段也是可以的)
a[i][0] <<= 1; a[i][1] <<= 1; a[i][0] |= 1; //这里一定要先对左区间的值去"|1"目的是排除了端点的干扰,例如这样子的点(我们只考虑x轴),(2,2),(2,3),这样子的时候,我们必须按照这样的顺序
if(a[i][1] < a[i][0]) swap(a[i][0], a[i][1]); //因为我们要的是对流出做出的控流
lsan[i] = a[i][0]; lsan[i + N] = a[i][1];
}
sort(lsan + 1, lsan + (N<<1) + 1);
diff = (int)(unique(lsan + 1, lsan + (N<<1) + 1) - lsan - 1);
T = diff + 1;
_add(S, 1, K, 0);
for(int i=1; i<=diff; i++) _add(i, i + 1, K, 0);
for(int i=1, L, R; i<=N; i++)
{
L = (int)(lower_bound(lsan + 1, lsan + diff + 1, a[i][0]) - lsan); R = (int)(lower_bound(lsan + 1, lsan + diff + 1, a[i][1]) - lsan);
_add(L, R, 1, -val[i]);
}
printf("%lld\n", EK());
return 0;
}