zoukankan      html  css  js  c++  java
  • [HEOI2016/TJOI2016]游戏

    嘟嘟嘟


    这题看数据范围大概能猜出来是网络流。
    看到网格图,就会想到这么两种解决方法:黑白染色或每一行每一列看成一个点。
    而不管用哪种方法,目的都是建立二分图,把冲突用连边表示出来,而同一侧的点之间没有冲突。


    对于这道题,黑白染色肯定gg,但是第二种方法也不是很好,毕竟同一行可能放多个炸弹的。换句话说,这种方法只能解决图中没有石头的情况。
    那有石头怎么办?这时候把每一行(列)再拆开一些,把没有'#'的一段看成一个点,然后连边即可。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 55;
    const int maxN = 5e3 + 5;
    const int maxe = 1e6 + 5;
    inline ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), last = ' ';
    	while(!isdigit(ch)) last = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(last == '-') ans = -ans;
    	return ans;
    }
    inline void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    char a[maxn][maxn];
    int n, m, cnt = 1, t;
    int l[maxn][maxn], r[maxn][maxn];
    bool vis[maxN];
    struct Edge
    {
    	int nxt, to, cap, flow;
    }e[maxe];
    int head[maxN], ecnt = -1;
    In void addEdge(int x, int y, int w)
    {
    	e[++ecnt] = (Edge){head[x], y, w, 0};
      	head[x] = ecnt;
      	e[++ecnt] = (Edge){head[y], x, 0, 0};
      	head[y] = ecnt;
    }
    
    int dis[maxN];
    In bool bfs()
    {
      	Mem(dis, 0); dis[0] = 1;
      	queue<int> q; q.push(0);
      	while(!q.empty())
        {
        	int now = q.front(); q.pop();
          	for(int i = head[now], v; i != -1; i = e[i].nxt)
        	{
          		if(!dis[v = e[i].to] && e[i].cap > e[i].flow)
            		dis[v] = dis[now] + 1, q.push(v);
        	}
        }
      	return dis[t];
    }
    int cur[maxN];
    In int dfs(int now, int res)
    {
    	if(now == t || res == 0) return res;
      	int flow = 0, f;
      	for(int& i = cur[now], v; i != -1; i = e[i].nxt)
        {
        	v = e[i].to;
          	if(dis[v] == dis[now] + 1 && (f = dfs(v, min(res, e[i].cap - e[i].flow))) > 0)
        	{
          		e[i].flow += f; e[i ^ 1].flow -= f;
          		flow += f; res -= f;
          		if(res == 0) break;
        	}
        }
      	return flow;
    }
    In int maxflow()
    {
      	int flow = 0;
      	while(bfs())
        {
        	memcpy(cur, head, sizeof(head));
          	flow += dfs(0, INF);
        }
      	return flow;
    }
    
    int main()
    {
    	Mem(head, -1);
    	n = read(), m = read();
    	for(int i = 1; i <= n; ++i) scanf("%s", a[i] + 1);
    	for(int i = 1; i <= n; ++i, ++cnt)
    		for(int j = 1; j <= m; ++j)
    			if(a[i][j] == '#') ++cnt;
    			else l[i][j] = cnt;
    	for(int j = 1; j <= m; ++j, ++cnt)
    		for(int i = 1; i <= n; ++i)
    			if(a[i][j] == '#') ++cnt;
    			else r[i][j] = cnt;
    	t = cnt;
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j)
    			if(a[i][j] == '*')
    			{
    				addEdge(l[i][j], r[i][j], 1);
    				if(!vis[l[i][j]]) vis[l[i][j]] = 1, addEdge(0, l[i][j], 1);	
    			} 
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j) if(a[i][j] == '*' && !vis[r[i][j]])
    		{
    			vis[r[i][j]] = 1;
    			addEdge(r[i][j], t, 1);
    		}
    	write(maxflow()), enter;
    	return 0;
    }
    
  • 相关阅读:
    The bean 'xxx' could not be injected as a 'xxx'because it is a JDK dynamic proxy that implements
    JQuery对象选择详细说明
    C#将image中的显示的图片转换成二进制
    选择一个图片文件,并且用PictureBox表示在Form上
    Android推送方案分析(MQTT/XMPP/GCM)
    [转载]什么是 Design Hackathon?
    脚本启动MySql服务
    Mysql数据库插入数据乱码问题,解决方案!
    MySQL自动备份脚本
    读取Excel模板,写入数据,并别输出另存为Excel文件
  • 原文地址:https://www.cnblogs.com/mrclr/p/10816783.html
Copyright © 2011-2022 走看看