HDU3739 Anti LIS 最大流Dinic

来源:互联网 发布:知豆汽车能开几年 编辑:程序博客网 时间:2024/04/30 01:27
Anti LISTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 577    Accepted Submission(s): 144Problem DescriptionHaven't you heard about Lost?Having written a article named <Summaries of ALL Algorithms>, Lost is good at solved by algorithm problems(?). One day, GXX asked Lost to work out the Longest Increasing Subsequence(for short, LIS) of a given sequence {A_1, A_2, ..., A_N}. Knowing this problem well, Lost simply copied a program from his article and solved the problem in seconds. So that GXX became frustrated. She wanted to cheat Lost by removing some elements from the original sequence to make Lost's answer go wrong. For convinience, she would like to remove least number of elements.InputThe beginning of the input is an integer T(T <= 10), which is the number of test cases. T cases are followed. The first line of each test case is an integer N (1 <= N <= 1,000), which denotes the length of the sequence. The second line is N integer A_1, A_2, ..., A_N, which denote the given sequence.OutputFor each test case, print a line contains a single integer which is the minimum number of the removed elements.Sample Input1610 10 20 1 2 2Sample Output2Authorftiasch & LostSourceACMDIY第二届群赛 

做完想吐血…搞了接近2天 好不容易思路正确了 还无限TLE…..
原来是自己写的Dinic板子太慢….换了个O(VF)的FF就过了..


和http://blog.csdn.net/LuRiCheng/article/details/54615690有点异曲同工
题意:给定序列 删除最少的数使得LIS长度变短
将每个数看做一个点 首先考虑拆点 每个点转化为 一个入点 和 一个出点
入点 有一条权值为1的边指向 出点
那最少删除多少个点 就转化为最少删除多少条边 可以用最大流求解
再考虑最大流最小割定理
假设LIS长度为len
如果将所有长度为len的路径上的边保留 其余所有边删除掉 那对这个剩余的图的最小割(破坏所有长度为len的路径) 就是使得原图LIS变短需要删除的点数

所以原问题就转化为筛选重要边,拆点,并求一遍最大流
但是问题来了 如果像HDU2485那样跑一遍Floyd显然会超时
考虑dis[i]为以第i个数结尾的LIS长度
但是如果源点只连接dis[i]=1的点,汇点只连接dis[i]=len的点 直接跑最大流 那就可以直接跑出结果,省去筛选边的过程

//新Dinic#include<iostream>#include<stdlib.h>#include<stdio.h>#include<string>#include<vector>#include<deque>#include<queue>#include<algorithm>#include<set>#include<map>#include<stack>#include<time.h>#include<math.h>#include<list>#include<cstring>#include<fstream>//#include<memory.h>using namespace std;#define ll long long#define ull unsigned long long#define pii pair<int,int>#define INF 1000000007#define pll pair<ll,ll>#define pid pair<int,double>const int N = 2*1e3 + 10;//点数const int M = 2*1e6;//边数*2(包括反向边)int level[N];//标号 level[i]:s到i的最短距离struct Edge{    int to,c,next;}edge[M];int head[N];int elem[N];inline void add_edge(int k,int u,int v,int c){    edge[k].to = v;    edge[k].c = c;    edge[k].next = head[u];    head[u] = k;}bool bfs(int s,int t,int n){//标号 计算level    deque<int>que;    fill(level,level+n+1,-1);    que.push_back(s);    level[s] = 0;    while(!que.empty()){        int u = que.front();        if(u == t){            return true;        }        que.pop_front();        for(int i = head[u];i!=-1;i = edge[i].next){            if(edge[i].c > 0 && level[edge[i].to] == -1){                level[edge[i].to] = level[u] + 1;                que.push_back(edge[i].to);            }        }    }    return false;}int dfs(int u,int t,int maxf){//u:所在的点 t:汇点 maxf:能流到u的流量    if(u == t){        return maxf;    }    int sum = 0;    for(int i = head[u];i!=-1;i = edge[i].next){        Edge&e = edge[i];        if(e.c>0 && level[e.to]==level[u]+1){            int f = dfs(e.to,t,min(maxf - sum,e.c));            sum += f;            edge[i].c -= f;            edge[i^1].c += f;            if(sum == maxf){//流量用完了                break;            }        }    }    level[u]=-1;    return sum;}int dinic(int s,int t,int n){//s:源点 t:汇点 n:点数    int ans = 0;    while(bfs(s,t,n)){        ans += dfs(s,t,2*INF);    }    return ans;}int dis[N];void built_G(int n){    fill(head,head+2*(n+1)+1,-1);    int tmp=0;    for(int i=1;i<=n;++i){//拆点        add_edge(tmp++,i,i+n,1);        add_edge(tmp++,i+n,i,0);    }    int maxlen=0;    for(int i=1;i<=n;++i){        dis[i]=1;        for(int j=1;j<i;++j){            if(elem[j]<elem[i]){                dis[i]=max(dis[i],dis[j]+1);            }        }        maxlen=max(maxlen,dis[i]);    }    for(int i=1;i<=n;++i){        for(int j=1;j<i;++j){            if(elem[j]<elem[i]&&dis[j]+1==dis[i]){                add_edge(tmp++,j+n,i,1);                add_edge(tmp++,i,j+n,0);            }        }    }    for(int i=1;i<=n;++i){//2*n+1:s   2*n+2:t        if(dis[i]==maxlen){            add_edge(tmp++,i+n,2*n+2,1);            add_edge(tmp++,2*n+2,i+n,0);        }        if(dis[i]==1){            add_edge(tmp++,2*n+1,i,1);            add_edge(tmp++,i,2*n+1,0);        }    }}int main(){    //freopen("/home/lu/Documents/r.txt","r",stdin);    //freopen("/home/lu/Documents/w.txt","w",stdout);    int T,n;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        for(int i=1;i<=n;++i){            scanf("%d",&elem[i]);        }        built_G(n);        printf("%d\n",               dinic(2*n+1,2*n+2,2*n+2));    }    return 0;}
#include<iostream>#include<stdlib.h>#include<stdio.h>#include<string>#include<vector>#include<deque>#include<queue>#include<algorithm>#include<set>#include<map>#include<stack>#include<time.h>#include<math.h>#include<list>#include<cstring>#include<fstream>//#include<memory.h>using namespace std;#define ll long long#define ull unsigned long long#define pii pair<int,int>#define INF 1000000007#define pll pair<ll,ll>#define pid pair<int,double>const int N = 2*1e3 + 10;//点数const int M = 2*1e6;//边数struct Edge{    int to,c,next;}edge[M];int head[N];int elem[N];inline void add_edge(int k,int u,int v,int c){    edge[k].to = v;    edge[k].c = c;    edge[k].next = head[u];    head[u] = k;}bool used[N];int dfs(int v,int t,int f){    if(v==t)        return f;    used[v]=true;    for(int i=head[v];i!=-1;i=edge[i].next){        Edge&e=edge[i];        if(used[e.to]==false&&e.c>0){            int d=dfs(e.to,t,min(f,e.c));            if(d>0){                e.c-=d;                edge[i^1].c+=d; //给反向边增加流量                return d;            }        }    }    return 0;}int max_flow(int s,int t){//s源点 t汇点    int flow=0;    while(true){        fill(used,used+N+1,false);        int f=dfs(s,t,INF);        if(f==0)            return flow;        flow+=f;    }}int dis[N];void built_G(int n){    fill(head,head+2*(n+1)+1,-1);    int tmp=0;    for(int i=1;i<=n;++i){//拆点        add_edge(tmp++,i,i+n,1);        add_edge(tmp++,i+n,i,0);    }    int maxlen=0;    for(int i=1;i<=n;++i){//计算dis        dis[i]=1;        for(int j=1;j<i;++j){            if(elem[j]<elem[i]){                dis[i]=max(dis[i],dis[j]+1);            }        }        maxlen=max(maxlen,dis[i]);    }    for(int i=1;i<=n;++i){//添加内点之间的边        for(int j=1;j<i;++j){            if(elem[j]<elem[i]&&dis[j]+1==dis[i]){                add_edge(tmp++,j+n,i,1);                add_edge(tmp++,i,j+n,0);            }        }    }    for(int i=1;i<=n;++i){//s:2*n+1  t:2*n+2        if(dis[i]==maxlen){//连接到汇点            add_edge(tmp++,i+n,2*n+2,1);            add_edge(tmp++,2*n+2,i+n,0);        }        if(dis[i]==1){//连接到源点            add_edge(tmp++,2*n+1,i,1);            add_edge(tmp++,i,2*n+1,0);        }    }}int main(){    //freopen("/home/lu/Documents/r.txt","r",stdin);    //freopen("/home/lu/Documents/w.txt","w",stdout);    int T,n;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        for(int i=1;i<=n;++i){            scanf("%d",&elem[i]);        }        built_G(n);        printf("%d\n",               max_flow(n*2+1,n*2+2));    }    return 0;}
0 0
原创粉丝点击