[NOIP2010]引水入城

传送门
思路:拿到这道题我就开始想不到正解就开始应该怎么搜(汗),不过还是好,能拿到70分(因为我舍弃了一种情况,就是从一个蓄水站往下走到另外一个沿湖城市,这种搜了很花时间)。听到正解发现我的思路真是不够,真是不行,我们可以发现每一个沿海城市能够到达的城市是连续的,所以我们就可以用一个N³搜索将原问题转化为一个区间覆盖问题,然后就可以水过了。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 250005
#define MAXM 1000005
int dd[4][2] = {0,1,0,-1,1,0,-1,0};
int mp[505][505], sx[505][505], sy[505][505], I, ld[505], rd[505], n, m;
int col[505];
bool vis[505][505];
bool dfs(int x, int y)
{
    if(vis[x][y] && x != 1) return sx[x][y];
    vis[x][y] = 1;
    if(x == 1) return 1;
    for(int i = 0; i < 4; i ++)
    {
        int tx = x + dd[i][0], ty = y + dd[i][1];
        if(tx < 1 || tx > n || ty > m || ty < 1) continue;
        if(mp[tx][ty] > mp[x][y]) if(dfs(tx, ty)) {sx[x][y] = tx, sy[x][y] = ty; break;}
    }
    return sx[x][y];
}
int ans = 0x3f3f3f3f;
struct E
{
    int l, r;
    bool operator < (const E rhs) const
    {
        return l < rhs.l;
    }
}e[505];
int L, R, cnt, dp[505];
void dfs1(int x, int y)
{
    if(x == n)
    {
        if(L > y) L = y;
        if(R < y) R = y;
    }
    for(int i = 0; i < 4; i ++)
    {
        int tx = x + dd[i][0], ty = y + dd[i][1];
        if(tx < 1 || tx > n || ty > m || ty < 1) continue;
        if(mp[tx][ty] < mp[x][y]) dfs1(tx, ty);
    }
    return;
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++)
            scanf("%d", &mp[i][j]);
    if(n == 1)
    {
        int answer = 0;
        for(int i = 1; i <= m; i ++)
            if(mp[1][i] >= mp[1][i-1] && mp[1][i] >= mp[1][i+1]) answer ++;
        printf("1\n%d\n", answer);
        return 0;
    }
    int flag = 0;
    for(int i = 1; i <= m; i ++)
        if(dfs(n, i)) flag ++;
    if(flag != m)
    {
        printf("0\n%d\n", m - flag);
        return 0;
    }
    for(int i = 1; i <= m; i ++)
    {
        L = 505, R = -1;
        dfs1(1, i);
        if(R != -1) {e[++ cnt].l = L;e[cnt].r = R;}
    }
    memset(dp, 0x3f, sizeof dp);
    dp[0] = 0;
    for(int i = 1; i <= m; i ++)
        for(int j = 1; j <= cnt; j ++)
            if(i >= e[j].l && i <= e[j].r && dp[i] > dp[e[j].l-1] + 1)
                dp[i] = dp[e[j].l-1] + 1;
    printf("1\n%d\n", dp[m]);
    return 0;
}

你可能感兴趣的:(noip,引水入城)