BZOJ 1930: [Shoi2003] pacman eating peas maximum cost maximum flow

title

BZOJ 1930
LUOGU 4066
Description

Two PACMAN eat peas. In the beginning, PACMAN in the origin of coordinates of the lower left, the Peas are in the upper right. PACMAN come Peas at will eat it. PACMAN walking route is very strange, can only go right or go up, they can not walk routes intersect. PACMAN help you calculate these two, they both add up to the maximum number of beans can be eaten.

Input

Conduct a first integer N, the number of Peas. Next N lines of a pair of positive integers, denotes the i th coordinate Peas. Peas coordinate any two will not coincide.

Output

Peas only one row comprises a number of integer, i.e. up to two eaten together PACMAN

Sample Input

8
8 1
1 5
5 7
2 2
7 8
4 6
3 3
6 4

Sample Output

7

HINT

Here Insert Picture DescriptionN < = 2000

analysis

At first glance, the cost of streaming version of passing notes, but not required routes intersect, but in fact does not matter, we can two routes intersect converted into two lines do not intersect (of course, at the intersection not so much pay attention to the.)

Built map:

  1. Each point split into two, an even flow of between 1, for the cost of the edge 1;
  2. If the \ (A \) departing reach \ (B \) , will be \ (A \) is connected to the point \ (B \) of the point;
  3. Running cost flow, however, it is clear that too many points, easily \ (TLE \) .
  4. So, we consider pruning (I do not know the word to use here is good, they say online, ┐ ( '~ `;) ┌): If \ (a \) able to \ (b \) , \ (B \) able to \ (C \) , apparently \ (a \) to \ (C \) will not need to connect the side;
  5. Only this is the case, does not work, because a point is possible through several times, it is also connected to a flow between two points of a point after the split point 1 at a cost edge 0;
  6. That's all.

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10,maxm=1e6+10,inf=0xcfcfcfcf,INF=0x3f3f3f3f;
 
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1, ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f; 
}
 
template<typename T>inline void write(T x)
{
    if (!x) { putchar('0'); return ; }
    if (x<0) putchar('-'), x=-x;
    T num=0, ch[20];
    while (x) ch[++num]=x%10+48, x/=10;
    while (num) putchar(ch[num--]);
}
 
int ver[maxm<<1],edge[maxm<<1],Next[maxm<<1],cost[maxm<<1],head[maxn],len=1;
inline void add(int x,int y,int z,int c)
{
    ver[++len]=y,edge[len]=z,cost[len]=c,Next[len]=head[x],head[x]=len;
    ver[++len]=x,edge[len]=0,cost[len]=-c,Next[len]=head[y],head[y]=len;
}
 
int s,t,ss,tt;
int dist[maxn],incf[maxn],pre[maxn];
bool vis[maxn];
inline bool spfa()
{
    memset(dist,0xcf,sizeof(dist));
    memset(vis,0,sizeof(vis));
    queue<int>q;q.push(s);
    dist[s]=0,vis[s]=1,incf[s]=1<<30;
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=0;
        for (int i=head[x]; i; i=Next[i])
        {
            if (!edge[i]) continue;
            int y=ver[i];
            if (dist[y]<dist[x]+cost[i])
            {
                dist[y]=dist[x]+cost[i];
                incf[y]=min(incf[x],edge[i]);
                pre[y]=i;
                if (!vis[y]) q.push(y),vis[y]=1;
            }
        }
    }
    if (dist[t]==inf) return false;
    else return true;
}
 
long long maxflow,ans;
inline void update()
{
    int x=t;
    while (x!=s)
    {
        int i=pre[x];
        edge[i]-=incf[t];
        edge[i^1]+=incf[t];
        x=ver[i^1];
    }
    maxflow+=incf[t];
    ans+=dist[t]*incf[t];
}
 
struct Orz{int x,y;}o[maxn];
inline bool cmp(Orz a,Orz b)
{
    return a.x<b.x || (a.x==b.x&&a.y<b.y);
}
 
int main()
{
    int n;read(n);
    s=0,t=n<<1|1;
    ss=t+1,tt=ss+1;
    for (int i=1; i<=n; ++i)
    {
        read(o[i].x),read(o[i].y);
        add(ss,i,1,0),add(i,i+n,1,1);//只有第一次经过才能拿到价值
        add(i,i+n,1,0),add(i+n,t,1,0);
    }
    sort(o+1,o+n+1,cmp);
    add(s,ss,2,0),add(t,tt,2,0);//此处容量为2,限制最多两条路线
    for (int i=1; i<=n; ++i)
    {
        int limy=INF;
        for (int j=i+1; j<=n; ++j)
        {
            if (o[j].y<limy && o[j].y>=o[i].y) add(i+n,j,2,0);
            if (o[j].y>=o[i].y) limy=min(limy,o[j].y);//更低则必须加边
        }
    }
    while (spfa()) update();
    write(ans),puts("");
    return 0;
}

Guess you like

Origin www.cnblogs.com/G-hsm/p/11323283.html