Go Running
题目大意
一些人在跑步,从任意一个位置开始,向左或向右跑,速度都为1 m/s。
现在已经知道在ti 时刻xi位置上出现了至少一个人,问最少有多少人在跑步
题解
先说一说比赛的时候的不足:
想到了往右跑的人在任意时刻 t - x 一定是相等的。
想到了往左跑的人在任意时刻 t + x 一定是相等的。
现在就是找一些值覆盖这n个点。。
然后就不会了,感觉有点像二分图,但是一直不知道怎么搞,像是脑子死机了一样。还有对时间复杂度理解的不够,一直认为1e5跑网络流会tle,可是二分图上的网络流复杂度为n * sqrt(n) ;
然后这道题就出不来了。总之:我好菜
其实再给t - x 与t + x连边,找个最小点覆盖(最大匹配)就好了。。
现在才是真的题解
可以以ti为横坐标xi为纵坐标把点表示在二维坐标系上,然后可以看出一个点往右走会延伸出一条斜率为1的直线,往左走会有一条斜率为-1的直线覆盖。
然后 找最少的斜率为1或-1的直线覆盖所有的点就好了。。
然后把坐标系旋转一下,会变成选一些横着的线和竖着的线覆盖所有点,然后就是找一些x,y覆盖所有的点。可以每个点的x和y连边跑最小覆盖数。
二分图里 最小覆盖数 = 最大匹配数
然后跑个最大匹配就好。
这个跟上面的理论其实一样的。。
怎么找覆盖问题,,是我做的题太少了,
代码:
#include<algorithm>
#include<cstring>
#include <iostream>
#include <cstdio>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef unsigned long long ull;
typedef set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void wenjian(){
freopen("concatenation.in","r",stdin);freopen("concatenation.out","w",stdout);}
void tempwj(){
freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){
return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){
a %= mod;ll ans = 1;while(b){
if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{
bool operator()(const pii & a, const pii & b){
return a.second < b.second;}};
int lb(int x){
return x & -x;}
//friend bool operator < (Node a,Node b) 重载
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const int maxn = 5e5+10;
pii pp[maxn];
std::vector<int> v1;
std::vector<int> v2;
int getid1(int x)
{
return lower_bound(v1.begin(),v1.end(),x) - v1.begin() + 1;
}
int getid2(int x)
{
return lower_bound(v2.begin(),v2.end(),x) - v2.begin() + 1;
}
struct Edge
{
int id,val,nex;
}edge[maxn << 2];
int cnt;
int head[maxn];
void add(int x,int y,int val)
{
edge[cnt].id = y;
edge[cnt].val = val;
edge[cnt].nex = head[x];
head[x] = cnt ++ ;
}
int n,m,s,t;
int dep[maxn];
queue<int> qq;
bool bfs()
{
for (int i = 1; i <= n; i ++ )
{
dep[i] = 0;
}
qq.push(s);
dep[s] = 1;
while(!qq.empty())
{
int x = qq.front();
qq.pop();
for (int i = head[x]; ~i; i = edge[i].nex)
{
int v = edge[i].id;
if(edge[i].val && dep[v] == 0)
{
dep[v] = dep[x] + 1;
qq.push(v);
}
}
}
// printf("%d\n",dep[t]);
if(dep[t] == 0)
return false;
return true;
}
int dinic(int x,int fl)
{
if(x == t)
return fl;
int s = 0;
for (int i = head[x]; ~i; i = edge[i].nex)
{
int v = edge[i].id;
if(edge[i].val && dep[v] == dep[x] + 1)
{
int p = dinic(v,min(fl,edge[i].val));
s += p;
edge[i].val -= p;
edge[i^1].val += p;
fl -= p;
}
}
if(s == 0)
{
dep[x] = 0;
return 0;
}
else
return s;
}
int getans()
{
int ans = 0;
while(1)
{
if(!bfs())
break;
// printf("%d\n", );
ans += 1ll * dinic(s,inf);
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
v1.clear();
v2.clear();
int nn;
scanf("%d",&nn);
for (int i= 1; i <= nn; i ++ )
{
int x,y;
scanf("%d%d",&x,&y);
pp[i].st = x + y;
pp[i].sd = x - y;
v1.pb(pp[i].st);
v2.pb(pp[i].sd);
}
sort(v1.begin(),v1.end());
v1.erase(unique(v1.begin(),v1.end()),v1.end());
int m = v1.size();
sort(v2.begin(),v2.end());
v2.erase(unique(v2.begin(),v2.end()),v2.end());
int m2 = v2.size();
n = m + m2;
s = m + m2 + 1;
t = m + m2 + 2;
n += 2;
for (int i= 1; i <= n; i ++ )
head[i] = -1;
cnt = 0;
for(int i =1 ; i <= m; i ++ )
{
add(s,i,1);
add(i,s,0);
}
for(int i = 1; i <= nn; i ++ )
{
int x = getid1(pp[i].st);
int y = getid2(pp[i].sd) + m;
// printf("%d %d\n",x,y);
add(x,y,1);
add(y,x,0);
}
for(int i = m + 1; i <= m + m2; i ++ )
{
add(t,i,0);
add(i,t,1);
}
printf("%d\n",getans());
}
}