题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2849
题 意:给出一个矩阵,每一个值代表一台电脑代表它能够抵御病毒几天(值是负的),已经被一种病毒感染的电脑不会再被其它病毒感染,但是它无法阻拦其它病毒去感染其它电脑,然后有两种病毒{1,2,3,....1000}种的任意两种,病毒编号小的先去感染,但是肯定不同种类,第一天有两台电脑,病毒是可以传染的,第一天只能感染抵御一天的电脑,第二天才能感染只能抵御2天以及2天以下的,第三天能感染只能抵御3天以及3天以下的电脑,所有电脑被感染后 会有 Q个提问, 每一个提问 会问你 此病毒 最终感染了几台电脑。
思 路:可以采用优先队列加BFS的方法来求解。定义两个数,感染的天数与病毒编号作为优先队列的依据。天数越少,病毒编号越小,则优先级越高。但一台电脑无法在感染时,比较它周围无法被感染的电脑无法抵挡的时刻,在更新自己的天数,直接进行遍历。
代码如下:
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <sstream>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long LL;
#define mod 999999
int vis[555][555];
int dx[4] = { 1, -1, 0, 0 };
int dy[4] = { 0, 0, 1, -1 };
int n, m;
struct node
{
int l, r, v, day;
bool operator < ( const node &a ) const//定义优先队列的优先级
{
if( day != a.day ) return day > a.day;
return v > a.v;
}
};
priority_queue<node>que;
void BFS()
{
node x;
while( !que.empty() )
{
x = que.top();
int k = -mod;//在电脑无法再次感染的时候使用
que.pop();
node temp;
for( int i = 0; i < 4; i ++ )
{
temp.l = x.l + dx[i];
temp.r = x.r + dy[i];
if( temp.l > 0 && temp.l <= n && temp.r > 0 && temp.r <= m && vis[temp.l][temp.r] < 0 )
{
if( x.day + vis[temp.l][temp.r] >= 0 )
{
temp.v = x.v;//传播病毒的编号
temp.day = x.day;//传播病毒的感染天数
vis[temp.l][temp.r] = x.v;//更新矩阵防止重复计算,也是为了便于计算结果
que.push( temp );
}
else{
if( vis[temp.l][temp.r] > k ) k = vis[temp.l][temp.r];//比较该电脑周围电脑可以再次的时刻
}
}
}
if( k > -mod ) //更新病毒再次感染的天数
{
x.day = -k;
que.push( x );
}
}
}
int main()
{
while( scanf ( "%d %d", &n, &m ) != EOF )
{
while( !que.empty() )//清空队列
que.pop();
for( int i = 1; i <= n; i ++ )
for( int j = 1; j <= m; j ++ )
{
scanf ( "%d", &vis[i][j] );
if( vis[i][j] > 0 )
{
node x;
x.l = i;
x.r = j;
x.v = vis[i][j];//病毒编号
x.day = 1;//感染天数
que.push( x );
}
}
BFS();
int T;
scanf ( "%d", &T );
while( T-- )
{
int ap;
scanf ( "%d", &ap );
int ans = 0;
for( int i = 1; i <= n; i ++ )
for( int j = 1; j <= m; j ++ )
if( vis[i][j] == ap ) ans++;
printf("%d\n", ans );
}
}
return 0;
}