Zombie March
Zombies have placed themselves at every junction in New York. Each junction 'i' initially has a presence of a
i
number of zombies. At every timestep each zombie randomly chooses one of its neighboring junctions and walks towards it. Each neighboring junction is choosen by the zombie with an equal probability. In order to safegaurd the citizens of New York we need to find out the expected number of zombies at every junction after 'k' timesteps.
The network of New York is given as an edge list.
Input Format:
t-> 'T' test cases, t test cases follow.
n, m, k- > number of junctions(nodes) of New York, number of roads (edges) and 'k' time steps.
Followed by m lines containing m edges, 1 edge in each line. Each edge is denoted by 2 integers that can range from 0 to n-1. All the edges are bidirectional. A node cannot connect itself.
Followed by n lines having initial number of Zombies at the location a
i.
Constraints:
1<=t<=5
5<=n<=100000
1<=m<= 200000
1<=k<=10000000
1<=a
i<=1000
Output Format:
No of zombies (rounded of to its nearest integer) in the Top 5 highly populated junctions after 'k' timesteps.
大概就是给你一张图,每个节点有一些僵尸,僵尸乱走,然后问你若干步后每个点僵尸的期望是多少。
每一步僵尸的状态只和前一步有关,跟前一步的前一步没有关系,所以满足马尔科夫性,这是一个典型的马尔科夫链。
既然知道了马尔科夫链就通过给定的数据可以得到状态转移矩阵,然后构造初始向量,乘以状态转移矩阵的K次方,就能得到最后的解。
但值得注意的是k的上限是10^7,是一个很大的数字,基本无法再规定时间内做出一个100000*100000的矩阵的如此高次幂。
因此我首先考虑的是矩阵处理。尝试进行对角化,也就是找到一个矩阵a和b使得 a*b*a^-1=X ,其中X就是原矩阵。
但是失败了,一是因为这个矩阵的秩是否为n,是否能进行对角化,二是这个对角化的过程编程实在是太过于复杂。
所以就要用其它的思路。
考虑到题目必然是有解的,其中一定还有什么信息还没用到,这些信息应该能当做突破点。
注意到题目的要求并没有让你求具体的期望,只要求将期望四舍五入到整数即可,所以或许不需要迭代k次,只需要迭代到一个收敛的状态即可。
那么收敛的状态是否存在呢?
答案是肯定的,根据马尔科夫链稳态存在的条件即可判断。
所谓的稳态存在的条件就是:在不可约的马尔科夫链中(如果图有不可达的区域,给定起始点将不在这个起始点所在的联通分量上的其余点都可以约掉),给定任意i,j,存在一个整数m,使得Pij(m)>0,若这个成立则此马尔科夫链必存在稳态。
换句话说,就是一个僵尸能跑到这个图的联通分量上的所有点,则条件成立,因为题目中说明了边都是双向的,因此条件一定成立。(其实这个论述也不严谨,比如n=2的情况就不成立,但好在题目中n是大于等于5的)
因此,在若干步后,此链会达到稳态,但同时我们也不知道在给定的k步内是否能趋近于稳态。
因此程序中判断若两次迭代后四舍五入的值相同,就认定是达到稳态,然后退出迭代。
代码提交通过,最长的用时大概是2S多一点。
数据存储上存储这个矩阵(稀疏矩阵),使用了哈希表和arraylist结合使用的方法,因为矩阵运算只涉及到乘,所以这样效率能高些。
代码如下:
import java.io.*;
import java.util.*;
public class Solution {
public static void main(String[] argvs) throws NumberFormatException, IOException
{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
//BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("D:/1.txt")));
int CASE=Integer.valueOf(br.readLine());
for(;CASE>0;CASE--)
{
String[] strs=br.readLine().split(" ");
int n=Integer.valueOf(strs[0]);
int m=Integer.valueOf(strs[1]);
int k=Integer.valueOf(strs[2]);
HashMap<Integer,ArrayList<point>> graph=new HashMap<Integer,ArrayList<point>>();
int[] nums=new int[n];
for(int i=0;i<=m-1;i++)
{
strs=br.readLine().split(" ");
nums[Integer.valueOf(strs[0])]++;
nums[Integer.valueOf(strs[1])]++;
point p1=new point(Integer.valueOf(strs[0]),1);
point p2=new point(Integer.valueOf(strs[1]),1);
ArrayList<point> al=graph.get(Integer.valueOf(strs[1]));
if(al==null)
{
al=new ArrayList<point>();
graph.put(Integer.valueOf(strs[1]), al);
}
al.add(p1);
al=graph.get(Integer.valueOf(strs[0]));
if(al==null)
{
al=new ArrayList<point>();
graph.put(Integer.valueOf(strs[0]), al);
}
al.add(p2);
}
for(Integer key : graph.keySet())
{
ArrayList<point> al=graph.get(key);
for(int i=0;i<=al.size()-1;i++)
{
al.get(i).value/=nums[al.get(i).y];
//System.out.println(key+" "+i+" "+al.get(i).value);
}
}
double[] newarray=new double[n];
double[] old=new double[n];
for(int i=0;i<=n-1;i++)
{
newarray[i]=-1;
old[i]=Integer.valueOf(br.readLine());
}
for(int i=0;i<=k-1;i++)
{
for(int j=0;j<=n-1;j++)
{
double t=0;
ArrayList<point> al=graph.get(j);
if(al==null)
{
newarray[j]=0;
continue;
}
for(int h=0;h<=al.size()-1;h++)
{
t+=al.get(h).value*old[al.get(h).y];
}
newarray[j]=t;
}
if(canfinish(newarray,old))
{
break;
}
old=newarray;
newarray=new double[n];
}
ArrayList<Integer> al=new ArrayList<Integer>();
for(int i=0;i<=old.length-1;i++)
{
al.add(near(old[i]));
}
Collections.sort(al);
for(int i=0;i<=4 ;i++)
{
System.out.print(al.get(al.size()-1-i)+" ");
}
System.out.println();
}
}
private static boolean canfinish(double[] a1,double[] a2)
{
for(int i=0;i<=a1.length-1;i++)
{
if(near(a1[i])!=near(a2[i]))
return false;
}
return true;
}
private static int near(double a)
{
if(a-(int)a>0.5)
{
return (int)a+1;
}
return (int)a;
}
private static class point
{
int y;
double value;
public point(int a,double b)
{
y=a;
value=b;
}
}
}