题目链接:
http://codeforces.com/problemset/problem/173/B
题意:
给你一个n*m的地图,现在有一束激光从左上角往左边射出,每遇到‘#’,你可以选择光线往四个方向射出,或者什么都不做,问最少需要多少个‘#’往四个方向射出才能使关系在n行往右边射出。
题解:
以行和列建二分图,如果str[i][j]=='#',则从i节点到j节点建一条双向边,权值都为1。然后对二分图跑一遍最短路。
代码:
#include<iostream> #include<cstring> #include<vector> #include<algorithm> #include<queue> using namespace std; const int maxn = 2222; vector<int> G[maxn]; char str[maxn][maxn]; int n, m; int inq[maxn], d[maxn]; int spfa() { queue<int> Q; memset(inq, 0, sizeof(inq)); memset(d, 0x7f, sizeof(d)); int ma = d[0]; d[1] = 0; inq[1] = 1; Q.push(1); while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if (d[v] > d[u] + 1) { d[v] = d[u] + 1; if (!inq[v]) inq[v]=1,Q.push(v); } } } if (d[n] >= ma) return -1; return d[n]; } void init() { for (int i = 0; i <= n + m + 1; i++) G[i].clear(); } int main() { while (scanf("%d%d", &n, &m) == 2 && n) { init(); for (int i = 1; i <= n; i++) scanf("%s", str[i] + 1); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (str[i][j] == '#') { G[i].push_back(j + n); G[j + n].push_back(i); } } } int ans = spfa(); printf("%d\n", ans); } return 0; }