HDU 2254-奥运(有向图的邻接矩阵+矩阵乘法)

奥运

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3235    Accepted Submission(s): 826


Problem Description
北京迎来了第一个奥运会,我们的欢呼声响彻中国大地,所以今年的奥运金牌 day day up!
比尔盖兹坐上鸟巢里,手里摇着小纸扇,看的不亦乐乎,被俺们健儿的顽强拼搏的精神深深的感动了。反正我的钱也多的没地方放了,他对自己说,我自己也来举办一个奥运会,看谁的更火。不过他的奥运会很特别:
1 参加人员必须是中国人;
2 至少会加法运算(因为要计算本人获得的金牌数)
他知道中国有很多的名胜古迹,他知道自己在t1 到 t2天内不可能把所有的地方都玩遍,所以他决定指定两个地方v1,v2,如果参赛员能计算出在t1到t2天(包括t1,t2)内从v1到v2共有多少种走法(每条道路走需要花一天的时间,且不能在某个城市停留,且t1=0时的走法数为0),那么他就会获得相应数量的金牌,城市的总数<=30,两个城市间可以有多条道路
,每条都视为是不同的。
 

Input
本题多个case,每个case:
输入一个数字n表示有n条道路 0<n<10000
接下来n行每行读入两个数字 p1,p2 表示城市p1到p2有道路,并不表示p2到p1有道路 (0<=p1,p2<2^32)
输入一个数字k表示有k个参赛人员
接下来k行,每行读入四个数据v1,v2,t1,t2 (0<=t1,t2<10000)
 

Output
对于每组数据中的每个参赛人员输出一个整数表示他获得的金牌数(mod 2008)
 

Sample Input
  
  
6 1 2 1 3 2 3 3 2 3 1 2 1 3 1 2 0 0 1 2 1 100 4 8 3 50
 

Sample Output
  
  
0 1506 0
 

Source
 

Recommend

题意:因为是中文题,所以自己看题面吧Orz。。。

题解:一开始是没有思路的,但是数据范围挺大的,又不能暴力搞,隐约觉得要转换成矩阵搞,之前好像遇到过类似题,但是当时没有深究,导致现在仍然不会写。。。。所以说还是不要求快的好,于是重做相似题时,翻了一些PPT和博客,算是懂了一些,不过具体证明我觉得没必要字字弄清。。

一个比较好懂的ppt :图的矩阵表示
本题的思路和解法就是将这个有向图的邻接矩阵给列出来即可,听起来感觉很厉害,其实就是有关系的两点在邻接矩阵中的值为1,不相关的为0,因为该矩阵的一次方就是任意两点一天能到达的情况,第二天以此类推,呢本题就是求该邻接矩阵的t1~t2次方了,还有个注意的地方是城市的标号较大,需要离散化一波(注意去除重点),剩下的就是矩阵乘法了。。

#include<map>        
#include<stack>        
#include<queue>      
#include<vector>        
#include<math.h>        
#include<stdio.h>      
#include<iostream>    
#include<string.h>        
#include<stdlib.h>        
#include<algorithm>        
using namespace std;        
typedef long long  ll;        
#define inf 1000000000        
#define mod 2008      
#define maxn  10005    
#define lowbit(x) (x&-x)        
#define eps 1e-10 
struct node
{
	int x[35][35];
}b[maxn],tmp;
struct edge
{
	int x,y;
}a[maxn];
int pos[105*100],n,cnt;
int sech(int l,int r,int x)
{  
    while(l<=r)
	{  
        int m=(l+r)/2;
        if(pos[m]==x)  
            return m;  
        else if(pos[m]<x)  
            l=m+1;  
        else  
            r=m-1; 
    }  
    return -1;  
}  
void init()
{
	memset(tmp.x,0,sizeof(tmp.x));
	sort(pos,pos+cnt);
	cnt=unique(pos,pos+cnt)-pos;
	for(int i=0;i<n;i++)
	{
		int x=sech(0,cnt-1,a[i].x);
		int y=sech(0,cnt-1,a[i].y);
		tmp.x[x][y]++;
	}
}
node q(node a,node b)
{
	node c;
	int i,j,k;
	for(i=0;i<cnt;i++)
		for(j=0;j<cnt;j++)
		{
			c.x[i][j]=0;
			for(k=0;k<cnt;k++)
				c.x[i][j]+=a.x[i][k]*b.x[k][j];
			c.x[i][j]%=mod;
		}
	return c;
}
void multi()
{
	b[0]=tmp;
	for(int i=1;i<=10000;i++)
		b[i]=q(b[i-1],tmp);
}
void work()
{
	init();
	multi();
	int k,v1,v2,t1,t2,i,sum;
	scanf("%d",&k);
	while(k--)
	{
		sum=0;
		scanf("%d%d%d%d",&v1,&v2,&t1,&t2);
		if(t1>t2 || t2<=0)
		{
			printf("0\n");
			continue;
		}
		int x=sech(0,cnt-1,v1);
		int y=sech(0,cnt-1,v2);
		if(x==-1 || y==-1)
		{
			printf("0\n");
			continue;
		}
		for(i=t1-1;i<t2;i++)
			sum=(sum+b[i].x[x][y])%mod;
		printf("%d\n",sum);
	}
}
int  main(void)
{
	while(scanf("%d",&n)!=EOF)
	{
		cnt=0;
		for(int i=0;i<n;i++)
		{
			scanf("%d%d",&a[i].x,&a[i].y);
			pos[cnt++]=a[i].x;
			pos[cnt++]=a[i].y;
		}
		work();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值