zoukankan      html  css  js  c++  java
  • BZOJ 1565: [NOI2009]植物大战僵尸


    题目


    1565: [NOI2009]植物大战僵尸

    Time Limit: 10 Sec  Memory Limit: 64 MB

    Description

    Input

    Output

    仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。

    Sample Input

    3 2
    10 0
    20 0
    -10 0
    -5 1 0 0
    100 1 2 1
    100 0

    Sample Output

    25

    HINT

    在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1)。 
    一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 。共得到能源收益为(-5)+20+10 = 25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。 
    【大致数据规模】
    约20%的数据满足1 ≤ N, M ≤ 5;
    约40%的数据满足1 ≤ N, M ≤ 10;
    约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。


    题解


    这道题是最大权闭合子图,求一个最后没有出度的子图。用网络流来做,将所有点之间的边流量为INF,点权为正的连原点,流量为点权,点权为负的连汇点,流量为绝对值。答案为所有正点权和-最大流。但是这道题目还有环保护的问题,一旦环保护了,那么都不可以取,跑最大流会坑!我们要用拓扑排序来处理,最后不断的去掉入度为0的点,得到新的入度为0的点,一些点入度总是不能为0说明在环内,要去掉。这样之后跑最大流就好!【我做的时候拓扑排序思路不是太清晰QAQ


    代码


    /*Author:WNJXYK*/
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    
    #define LL long long
    #define Inf 2147483647
    #define InfL 10000000000LL
    
    inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
    inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
    inline int remin(int a,int b){if (a<b) return a;return b;}
    inline int remax(int a,int b){if (a>b) return a;return b;}
    inline LL remin(LL a,LL b){if (a<b) return a;return b;}
    inline LL remax(LL a,LL b){if (a>b) return a;return b;}
    
    const int Maxn=1000;
    const int Maxm=500000;
    int Ans=0;
    
    struct Edge{
    	int v,f,nxt;
    	Edge(){}
    	Edge(int a,int b,int c){v=a;f=b;nxt=c;}
    };
    Edge e[Maxm+10];
    int head[Maxn+10];
    int nume=1;
    inline void addEdge(int u,int v,int f){
    	e[++nume]=Edge(v,f,head[u]);
    	head[u]=nume;
    	e[++nume]=Edge(u,0,head[v]);
    	head[v]=nume;
    	//printf("MakeEdge %d -> %d : %d
    ",u,v,f);
    }
    
    int src;
    int sink;
    
    queue<int> que;
    int dist[Maxn+10];
    inline bool bfs(){
    	while(!que.empty()) que.pop();
    	memset(dist,-1,sizeof(dist));
    	que.push(src);
    	dist[src]=0;
    	while(!que.empty()){
    		int now=que.front();
    		//printf("BFS->%d
    ",now);
    		que.pop();
    		for (int i=head[now];i;i=e[i].nxt){
    			//printf("BFS Try->%d
    ",e[i].v);
    			int tp=e[i].v;
    			if (dist[tp]==-1 && e[i].f!=0){
    				dist[tp]=dist[now]+1;
    				que.push(tp);
    			}
    		}
    	}
    	return dist[sink]!=-1;
    }
    
    int dfs(int x,int delta){
    	int ret=0;
    	if (x==sink){
    		return delta;
    	}else{
    		for (int i=head[x];i;i=e[i].nxt){
    			int tp=e[i].v;
    			if (dist[tp]==dist[x]+1 && e[i].f!=0){
    				int dd=dfs(tp,remin(delta,e[i].f));
    				e[i].f-=dd;
    				e[i^1].f+=dd;
    				delta-=dd;
    				ret+=dd;
    			}
    		}
    	}
    	return ret;
    }
    
    inline int dinic(){
    	int ret=0;
    	while(bfs())ret+=dfs(src,Inf);
    	return ret;
    }
    
    int n,m;
    int score[35][35];
    struct MapEdge{
    	int x,y;
    	int nxt;
    	MapEdge(){}
    	MapEdge(int a,int b,int c){x=a;y=b;nxt=c;}
    };
    MapEdge me[Maxm+10];
    int MapNume=0;
    int MapHead[35][35];
    int inpoint[35][35];
    bool visited[35][35];
    
    inline void addMapEdge(int x,int y,int x1,int y1){
    	me[++MapNume]=MapEdge(x1,y1,MapHead[x][y]);
    	MapHead[x][y]=MapNume;
    	inpoint[x1][y1]++;
    }
    
    inline int point2id(int x,int y){
    	return (x-1)*m+y+1;
    }
    
    queue<pair<int,int> > MapQue;
    inline void spfaR(int x,int y){
    	//memset(visited,false,sizeof(visited));
    	while(!MapQue.empty()) MapQue.pop();
    	visited[x][y]=true;
    	MapQue.push(make_pair(x,y));
    	while(!MapQue.empty()){
    		int nowx=MapQue.front().first,nowy=MapQue.front().second;
    		//printf("TopSort->%d %d
    ",nowx,nowy);
    		MapQue.pop();
    		for (int i=MapHead[nowx][nowy];i;i=me[i].nxt){
    			int tx=me[i].x,ty=me[i].y;
    			if (inpoint[tx][ty]<=1){
    				addEdge(point2id(tx,ty),point2id(nowx,nowy),Inf);
    				inpoint[tx][ty]--;
    				visited[tx][ty]=true;
    				MapQue.push(make_pair(tx,ty));
    			}else{
    				addEdge(point2id(tx,ty),point2id(nowx,nowy),Inf);
    				inpoint[tx][ty]--;
    			}
    		}
    		
    	}
    }
    
    inline void solveRoundP(){
    		for (int i=1;i<=n;i++){
    			for (int j=1;j<=m;j++){
    				if (inpoint[i][j]<=0 && visited[i][j]==false){
    					spfaR(i,j);
    				} 
    			}
    		}	
    	
    	for (int i=1;i<=n;i++){
    		for (int j=1;j<=m;j++){
    			if (inpoint[i][j]<=0){
    				if (score[i][j]>=0){
    					addEdge(src,point2id(i,j),score[i][j]);
    					Ans+=score[i][j];
    				}else{
    					addEdge(point2id(i,j),sink,-score[i][j]);
    				}
    			}
    			///////Arrest
    			//if (inpoint[i][j]==0)
    				//printf("UsePoint->%d %d
    ",i,j);
    		}
    	}
    }
    
    
    int main(){
    	//freopen("pvz.in","r",stdin);
    	//freopen("pvz.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	src=1;
    	sink=n*m+2;
    	for (int i=1;i<=n;i++){
    		for (int j=1;j<=m;j++){
    			if (j>1) addMapEdge(i,j,i,j-1);
    			scanf("%d",&score[i][j]);
    			int w;
    			scanf("%d",&w);
    			for (int k=1;k<=w;k++){
    				int x,y;
    				scanf("%d%d",&x,&y);
    				x++;y++;
    				if (x!=i || y!=j-1) 
    					addMapEdge(i,j,x,y);
    			}
    		}
    	}
    	solveRoundP();
    	printf("%d
    ",Ans-dinic());
    	return 0;
    }
    




  • 相关阅读:
    关于微软 2012 暑期实习题第 5 题
    ZOJ 1608. Two Circles and a Rectangle
    在技术社区以外的博文中插入代码(把代码转换到 Html 文本)
    ZOJ 2240. Run Length Encoding
    C++中“引用”的底层实现
    采用路径模型实现遍历二叉树的方法
    ZOJ 简单题集合(四)
    ZOJ 3603. Draw Something Cheat
    关于类的虚函数表
    ZOJ 3499. Median
  • 原文地址:https://www.cnblogs.com/WNJXYK/p/4063919.html
Copyright © 2011-2022 走看看