M.J的blog

algorithm,ACM-ICPC
随笔 - 39, 文章 - 11, 评论 - 20, 引用 - 0
数据加载中……

TOJ 2469. Friends【并查集】

并查集或者DFS的题,大概是说有N个学生去订房间,只有朋友可以住一个房间。朋友关系具有传递性,如果A和B是朋友,B和C是朋友,那么A和C是朋友。问最后最少定多少个房间。
我用并查集做,却在最后犯了一个很不容易发觉的错误,最后还是找一个学姐才发现。看来以后一定得小心啊,太大意会很可怕的~
Code:
 1 #include<stdio.h>
 2 #include<string.h>
 3 struct student
 4 {
 5     int father,rank;
 6 }a[250];
 7 bool flag[250];
 8 void initial(int n)
 9 {
10     int i;
11     for(i=1;i<=n;i++){
12         a[i].father=i;
13         a[i].rank=1;
14     }
15 }
16 int find(int n)
17 {
18     while(a[n].father!=n)
19         n=a[n].father;
20     return n;  
21 }
22 void Union(int root1,int root2)
23 {
24     int t1,t2;
25     t1=find(root1);
26     t2=find(root2);
27     if(t1==t2) return ;
28     else{
29         if(a[t1].rank>a[t2].rank){
30             a[t2].father=t1;
31             a[t1].rank+=a[t2].rank;
32         }
33         else{
34             a[t1].father=t2;
35             a[t2].rank+=a[t1].rank;
36         }
37     }
38 }
39 int main()
40 {
41     int i,j,k,m,n,cas;
42     scanf("%d",&cas);
43     while(cas--){
44         scanf("%d%d",&n,&m);
45         initial(n);
46         for(i=1;i<=m;i++){
47             scanf("%d%d",&j,&k);
48             Union(j,k);
49         }
50         memset(flag,false,sizeof(flag));
51         k=0;
52         for(i=1;i<=n;i++){
53             if(!flag[find(i)]){
54                 k++;
55                 flag[find(i)]=true;
56             }
57         }
58         printf("%d\n",k);
59     }
60 }
61 

posted @ 2010-04-30 22:38 M.J 阅读(318) | 评论 (0)编辑 收藏

【图论】最短路和最小生成树

两个算法具有相当大的相似性,而且都用到了贪心思想,所以把他们放到一起。最短路常用的算法有dijkstra,bellman-ford,floyd。而最小生成树则是prim和kruskal。下面是各个算法的模板。
Dijkstra:
 1 #include<stdio.h>
 2 #include<string.h>
 3 #define INF 0x1f1f1f1f
 4 #define M 1001
 5 int map[M][M],dis[M];
 6 bool flag[M];
 7 void dijkstra(int s,int n,int t)            //s是源点,n是点的个数,t是目的点
 8 {
 9     int i,j,k,md,temp;
10     for(i=1;i<=n;i++)
11         dis[i]=INF;                        //初始化将所有dis置为无穷大,源点为0
12     dis[s]=0;
13     memset(flag,false,sizeof(flag));       //开始flag全部为false,表示集合为空
14     for(i=1;i<n;i++){                      //进行n-1次迭代,每次找出不在集合中的最小边
15         md=INF;                                           
16         for(j=1;j<=n;j++){
17             if(!flag[j]&&dis[j]<md){
18                 md=dis[j];
19                 temp=j;
20             }
21         } 
22         if(temp==t) break;                 //如果遇到目的点,可以跳出了
23         flag[temp]=true;                   //将这个最小边的点加入集合
24         for(j=1;j<=n;j++){
25             if(!flag[j]&&md+map[temp][j]<dis[j])    //对所有出边进行松弛操作
26                 dis[j]=md+map[temp][j];
27         }
28     }
29 }

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
相应的最小生成树的prim模板:

 1 #include<iostream>
 2 #define INF 0x1f1f1f1f
 3 #define M 1000
 4 using namespace std;
 5 double dis[M],map[M][M];
 6 bool flag[M];
 7 int prim(int s,int n)                        //s为起点,n为点的个数
 8 {
 9     int i,j,k,temp,md,total=0;
10     for(i=1;i<=n;i++)
11         dis[i]=map[s][i];                    //与最短路不同,而是将dis置为map[s][i]
12     memset(flag,false,sizeof(flag));
13     flag[s]=true;                            //将起点加入集合
14     for(i=1;i<n;i++){                        //依旧进行n-1次迭代,每次找到不在集合的最小边
15         md=INF;
16         for(j=1;j<=n;j++){
17             if(!flag[j]&&dis[j]<md){
18                 md=dis[j];
19                 temp=j;
20             }
21         }
22         flag[temp]=true;                      //将找到的最小边的点加入集合
23         total+=md;                            //并将这个边的权值加到total中
24         for(j=1;j<=n;j++)                     //松弛操作,注意与最短路不同
25             if(!flag[j]&&dis[j]>map[temp][j])
26                 dis[j]=map[temp][j];
27     }
28     return total;
29 }
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面是最短路的bellmen-ford算法,与dijkstra不同,bellman-ford可以运用于有负权值的图,不过复杂度很高,O(VE )... 慎用~(可以用SPFA,但是那个算法我掌握的不是很好:D)
Bellman-ford算法同样是对每条边进行N-1次松弛,当有权值为负时,对所有边进行N-1次松弛,如果dis还能更新,说明有负环。
Bellman-ford模板:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define INF 0x1f1f1f1f
 4 #define MAX 102
 5 #define MAXM 20008
 6 
 7 int dist[MAX];
 8 
 9 struct Edge{             //边结构体定义 
10     int u, v, w;
11     Edge(){}
12     Edge(int a, int b, int c):u(a), v(b), w(c){}
13 }edge[MAXM];
14 
15 int bellman_ford(int n, int m, int s)   //n个点、m条边、s为起点 
16 {
17     memset(dist, 0x1fsizeof(dist));    //初始化距离很大 
18     dist[s] = 0;
19     int i, j, u, v, f;
20     for (i = 1; i < n; ++i)         //迭代 n - 1 次,对每条边进行n-1次松弛
21     {
22            f = 0;
23          for (j = 0; j < m; ++j)
24            {
25          u = edge[j].u;
26          v = edge[j].v;
27              if (dist[v] > dist[u] + edge[j].w)  // 松弛操作 
28                 {
29              dist[v] = dist[u] + edge[j].w;
30                        f = 1;
31          }
32          }
33          if (!f) return 1;          //如果其中一次迭代没改变,停止
34     }
35     for(j = 0; j < m; ++j)     //再进行一次迭代 
36     {
37          u = edge[j].u;
38          v = edge[j].v;
39          if (dist[v] > dist[u] + edge[j].w)    //若还能松弛, 则存在负环 
40             return -1;                    //存在负环返回 -1 
41     }
42     return 1;       //没有负环返回 1 
43 }
算法结束后dist数组已经是最短路径。

posted @ 2010-04-30 18:54 M.J 阅读(1970) | 评论 (1)编辑 收藏

【数论内容】线性筛素数,线性筛欧拉函数,求前N个数的约数个数

先来最基本的线性筛素数,以后的算法其实都是基于这个最基本的算法:
 1 #include<stdio.h>
 2 #include<string.h>
 3 #define M 10000000
 4 int prime[M/3];
 5 bool flag[M];
 6 void get_prime()
 7 {
 8     int i,j,k;
 9     memset(flag,false,sizeof(flag));
10     k=0;
11     for(i=2;i<M;i++){
12         if(!flag[i])                            
13         prime[k++]=i;
14         for(j=0;j<k&&i*prime[j]<M;j++){
15             flag[i*prime[j]]=true;            
16             if(i%prime[j]==0)             
17                 break;
18         }
19     }
20 }
21 int main()
22 {}
 

利用了每个合数必有一个最小素因子,每个合数仅被它的最小素因子筛去正好一次,所以是线性时间。
代码中体现在: if(i%prime[j]==0) break;
-----------------------------------------------------------------------我是低调的分割线------------------------------------------------------------------------------------------
然后可以利用这种线性筛法求欧拉函数,需要用到以下几个性质:
//(1) 若(N%a==0 && (N/a)%a==0) 则有:E(N)=E(N/a)*a;
//(2) 若(N%a==0 && (N/a)%a!=0) 则有:E(N)=E(N/a)*(a-1); 
其中a是N的质因数。
关于欧拉函数还有以下性质:
(1) phi[p]=p-1;  (p为素数);
(2)若N=p^n(p为素数),则 phi[N]=(p-1)*p^(n-1);
关于欧拉函数,Wiki有很详细的介绍。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define M 10000000
 4 int prime[M/3],phi[M];
 5 bool flag[M];
 6 void get_prime()
 7 {
 8     int i,j,k;
 9     memset(flag,false,sizeof(flag));
10     k=0;
11     for(i=2;i<M;i++){
12         if(!flag[i]){                            
13             prime[k++]=i;
14             phi[i]=i-1;
15         }
16         for(j=0;j<k&&i*prime[j]<M;j++){
17             flag[i*prime[j]]=true;            
18             if(i%prime[j]==0){
19                 phi[i*prime[j]]=phi[i]*prime[j];
20                 break;
21             }
22             else
23                 phi[i*prime[j]]=phi[i]*(prime[j]-1);
24         }
25     }
26 }
27 int main()
28 {}

-----------------------------------------------------------------------我是低调的分割线-----------------------------------------------------------------------------------------
求约数个数略微复杂一点,但大体还是那个意思。
约数个数的性质,对于一个数N,N=p1^a1 + p2^a2 + ... + pn^an。其中p1 ,p2, p3... pn是N的质因数,a1 ,a2, a2,...an为相应的指数,则
                                                           div_num[N]=(p1+1)*(p2+1)*(p3+1)* ... *(pn+1);
结合这个算法的特点,在程序中如下运用:
  对于div_num:

(1)如果i|prime[j] 那么 div_num[i*prime[j]]=div_sum[i]/(e[i]+1)*(e[i]+2)                  //最小素因子次数加1
(2)否则 div_num[i*prime[j]]=div_num[i]*div_num[prime[j]]                                     //满足积性函数条件

  对于e:

(1)如果i|pr[j]  e[i*pr[j]]=e[i]+1; //最小素因子次数加1
(2)否则 e[i*pr[j]]=1;              //pr[j]为1次

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define M 10000000
 4 int prime[M/3],e[M/3],div_num[M];           // e[i]表示第i个素数因子的个数
 5 bool flag[M];
 6 void get_prime()
 7 {
 8     int i,j,k;
 9     memset(flag,false,sizeof(flag));
10     k=0;
11     for(i=2;i<M;i++){
12         if(!flag[i]){                            
13             prime[k++]=i;
14             e[i]=1;
15             div_num[i]=2;                       //素数的约数个数为2
16         }
17         for(j=0;j<k&&i*prime[j]<M;j++){
18             flag[i*prime[j]]=true;            
19             if(i%prime[j]==0){
20                 div_num[i*prime[j]]=div_num[i]/(e[i]+1)*(e[i]+2);
21                 e[i*prime[j]]=e[i]+1;
22                 break;
23             }
24             else{
25                 div_num[i*prime[j]]=div_num[i]*div_num[prime[j]];
26                 e[i]=1;
27             }
28         }
29     }
30 }
31 int main()
32 {}
33 
34 
35 
希望大家有所收获~~                        
 Made by  M.J

posted @ 2010-04-28 16:56 M.J 阅读(3732) | 评论 (11)编辑 收藏

TOJ 1129 Arbitrage(套汇问题Floyd)

dis[ ][ ]是图的邻接矩阵,其中不存在的边权值为正无穷大。
for(k = 0; k < n; k++)
      for(i = 0; i < n; i++)
            for(j = 0; j < n; j++)
                  if(dis[i][j] > dis[i][k] + dis[k][j])

                          dis[i][j] = dis[i][k] + dis[k][j];

时间复杂度 O(v^3)

 1 #include<iostream>
 2 #include<map>
 3 #include<vector>
 4 #include<string>
 5 #define M 0
 6 double ma[50][50],bi;
 7 using namespace std;
 8 bool floyd(int n)
 9 {
10     int i,j,k,m;
11 
12     for(i=1;i<=n;i++)
13         for(j=1;j<=n;j++)
14             for(k=1;k<=n;k++)
15                 if(ma[j][k]<ma[j][i]*ma[i][k])
16                     ma[j][k]=ma[j][i]*ma[i][k];
17     for(i=1;i<=n;i++)
18         if(ma[i][i]>1)
19             return true;
20     return false;
21 }
22 int main()
23 {
24     map<string,int>fuck;
25     int i,j,k,n,m,p,q,count=1;
26     string cash,cash2;
27     while(cin>>n&&n)
28     {
29         for(i=1;i<=n;i++)
30         {
31             cin>>cash;
32             fuck[cash]=i;
33         }
34         for(i=1;i<=n;i++)
35             for(j=1;j<=n;j++)
36                 ma[i][j]=ma[j][i]=M;
37         cin>>m;
38         for(i=1;i<=m;i++)
39         {
40             cin>>cash;
41             p=fuck[cash];
42             cin>>bi;
43             cin>>cash2;
44             q=fuck[cash2];
45             ma[p][q]=bi;
46         }
47         if(floyd(n))
48             cout<<"Case "<<count<<": Yes"<<endl;
49         else 
50             cout<<"Case "<<count<<": No"<<endl;
51         count++;
52     }
53 }
54 

posted @ 2010-04-25 23:27 M.J 阅读(437) | 评论 (0)编辑 收藏

POJ 2762. Balanced Lineup (区间求最值sparsetable算法)

啥也不说了,sparsetable算法的高效性,我真佩服那个发明它的人。Orz...

以下是关于这个算法的讲解(我也没理解透,回头细细品味吧)

RMQ(Range Minimum/Maximum Query)问题是求区间最值问题。你当然可以写个O(n)的(怎么写都可以吧=_=),但是万一要询问最值1000000遍,估计你就要挂了。这时候你可以放心地写一个线段树(前提是不写错)O(logn)的复杂度应该不会挂。但是,这里有更牛的算法,就是ST算法,它可以做到O(nlogn)的预处理,O(1)!!!地回答每个询问。

       来看一下ST算法是怎么实现的(以最大值为例):

       首先是预处理,用一个DP解决。设a[i]是要求区间最值的数列,f[i, j]表示从第i个数起连续2^j个数中的最大值。例如数列3 2 4 5 6 8 1 2 9 7 ,f[1,0]表示第1个数起,长度为2^0=1的最大值,其实就是3这个数。f[1,2]=5,f[1,3]=8,f[2,0]=2,f[2,1]=4……从这里可以看出f[i,0]其实就等于a[i]。这样,Dp的状态、初值都已经有了,剩下的就是状态转移方程。我们把f[i,j]平均分成两段(因为f[i,j]一定是偶数个数字),从i到i+2^(j-1)-1为一段,i+2^(j-1)到i+2^j-1为一段(长度都为2^(j-1))。用上例说明,当i=1,j=3时就是3,2,4,5 和 6,8,1,2这两段。f[i,j]就是这两段的最大值中的最大值。于是我们得到了动规方程F[i, j]=max(F[i,j-1], F[i + 2^(j-1),j-1]).

 

接下来是得出最值,也许你想不到计算出f[i,j]有什么用处,一般毛想想计算max还是要O(logn),甚至O(n)。但有一个很好的办法,做到了O(1)。还是分开来。如在上例中我们要求区间[2,8]的最大值,就要把它分成[2,5]和[5,8]两个区间,因为这两个区间的最大值我们可以直接由f[2,2]和f[5,2]得到。扩展到一般情况,就是把区间[L,R]分成两个长度为2^n的区间(保证有f[i,j]对应)。直接给出表达式:

k := ln(R-L+1) / ln(2);

ans := max(F[L,k], F[R - 2^k+1, k]);

这样就计算了从i开始,长度为2^t次的区间和从r-2^i+1开始长度为2^t的区间的最大值(表达式比较烦琐,细节问题如加1减1需要仔细考虑.

Code:

 1 #include<iostream>
 2 #include<cmath>
 3 #define M 100005
 4 int rmq1[M][30];
 5 int rmq2[M][30];
 6 int a[M];
 7 int N,Q,R,L;
 8 using namespace std;
 9 int max(int a,int b)
10 {
11     if(a>b) return a;
12     else   return b;
13 }
14 int min(int a,int b)
15 {
16     if(a<b) return a;
17     else    return b;
18 }
19 void DP(int N)
20 {
21     int i,j,k;
22     for(i=1;i<=int(log(double(N))/log(2.0));i++)
23         for(j=1;j<=N;j++)
24         {
25             rmq1[j][i]=max(rmq1[j][i-1],rmq1[j+int(pow(2.0,i-1))][i-1]);
26             rmq2[j][i]=min(rmq2[j][i-1],rmq2[j+int(pow(2.0,i-1))][i-1]);
27         }
28 }
29 int search(int i,int j)
30 {
31      int k=(int)(log((double)(j-i+1))/log(2.0));
32      return max(rmq1[i][k],rmq1[j-(1<<k)+1][k])-min(rmq2[i][k],rmq2[j-(1<<k)+1][k]);
33 }
34 int main()
35 {
36     int i,j,k;
37     scanf("%d%d",&N,&Q);
38     for(i=1;i<=N;i++)
39     {
40         scanf("%d",&a[i]);
41         rmq1[i][0]=a[i]; 
42         rmq2[i][0]=a[i];                                                  //初始化
43     }
44     DP(N);
45     while(Q--)
46     {
47         scanf("%d%d",&i,&j);
48         printf("%d\n",search(i,j));
49     }
50 }
51 

posted @ 2010-04-25 23:12 M.J 阅读(1521) | 评论 (2)编辑 收藏

TOJ 1353 the K-th city

求距离一个city第k近的city。根据dijkstra的特点,循环K+1次即找到了距源点距离第K近的。
Code:

 1 #include<iostream>
 2 #define M 1000000000
 3 #define MAX 202
 4 int map[MAX][MAX],dis[MAX];
 5 bool flag[MAX];
 6 void dijkstra(int n,int s,int key)       //  n is the number of point,and start from s ,key is the key-city
 7 {
 8     int i,j,k,temp,md;
 9     memset(flag,false,sizeof(flag));
10     for(i=0;i<MAX;i++)
11         dis[i]=M;
12     dis[s]=0;
13     for(i=1;i<=key+1;i++)
14     {
15         md=M;
16         for(j=0;j<n;j++)                       //找到距离当前最近的
17         { 
18             if(!flag[j]&&dis[j]<md)
19             {
20                 md=dis[j];
21                 temp=j;
22             }
23         }
24         flag[temp]=true;                      //将这个点加进来
25         for(j=0;j<n;j++)                      //松弛操作
26         {
27             if(!flag[j]&&md+map[temp][j]<dis[j])
28                 dis[j]=md+map[temp][j];
29         }
30     }
31     printf("%d\n",temp);
32 }
33 int main()
34 {
35     int i,j,k,m,n,p;
36     while(scanf("%d",&n)!=EOF)
37     {
38         if(n==0break;
39         scanf("%d",&m);
40         for(i=0;i<MAX-1;i++)
41             for(j=i+1;j<MAX;j++)
42                 map[i][j]=map[j][i]=M;
43         for(i=1;i<=m;i++)
44         {
45             scanf("%d%d%d",&j,&k,&p);
46             map[j][k]=map[k][j]=p;
47         }
48         scanf("%d",&k);
49         dijkstra(n,0,k);
50     }
51     return 0;
52 }
53 

posted @ 2010-04-25 23:08 M.J 阅读(132) | 评论 (0)编辑 收藏

TOJ 2831 Worm holes

题意是有n个农场,农场有N块地,其中M条路是双向的,S条路是单向的。双向的路权值为正,单向的路权值为负。需要判断有没有负环。

以下是bellman_ford算法,需要注意的地方在注释里边。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define INF 0x1f1f1f1f
 4 #define MAX 5500
 5 int dist[MAX/10];
 6 struct edge
 7 {
 8     int u,v,w; //u为起点 v为终点 w是权值
 9 }edge[MAX];
10 int bellman_ford2(int n,int m,int s) //n个点,m条边,起点是s
11 {
12     memset(dist,0x1f1f,sizeof(dist));
13     dist[s]=0;
14     int i,j,k,p,u,v;
15     bool flag;
16     for(i=1;i<n;i++)                         //n-1次迭代
17     {
18         flag=false;                          //用来标记某一次是否是更新
19         for(j=0;j<m;j++)                     //对每条边进行松弛,即迭代一次
20         {
21             u=edge[j].u;
22             v=edge[j].v;
23             if(dist[v]>dist[u]+edge[j].w)
24             {
25                 dist[v]=dist[u]+edge[j].w;
26                 flag=true;                     //如果这一次有某条边可以松弛
27             }
28         }
29         if(!flag)                            //如果某一次所有边都没有松弛,
30             return 1;                        // 可以确定没有负环,返回 1
31     }
32     flag=false;
33     for(i=0;i<m;i++)                        //对所有边进行第n次松弛
34     {
35         u=edge[i].u;
36         v=edge[i].v;
37         if(dist[v]>dist[u]+edge[i].w)
38         {
39             dist[v]=dist[u]+edge[i].w;
40             flag=true;
41         }
42         if(flag) return -1//如果还有更新,有负环 返回 -1
43     }
44     return 1//否则返回 1
45 }
46 int main()
47 {
48     int i,j,k,m,n,p,q,N,M;
49     int S;
50     scanf("%d",&n);
51     for(i=1;i<=n;i++)
52     {
53         scanf("%d%d%d",&N,&M,&S);
54         int t=0;
55         for(j=1;j<=M;j++)
56         {
57             scanf("%d%d%d",&p,&q,&k);
58             edge[t].u=p;                             //由于边是双向的,需要是两条
59             edge[t].v=q;
60             edge[t].w=k; t++;
61             edge[t].u=q;
62             edge[t].v=p;
63             edge[t].w=k; t++;
64     }
65     for(j=1;j<=S;j++)
66     {
67         scanf("%d%d%d",&p,&q,&k);
68         edge[t].u=p;
69         edge[t].v=q;
70         edge[t].w=-1*k; t++//单向的边权值为负
71     }
72     if(bellman_ford2(N,S+2*M,1)==-1//如果有负环 YES
73         printf("YES\n");
74     else
75         printf("NO\n");
76     }
77 }
78 

posted @ 2010-04-25 23:02 M.J 阅读(915) | 评论 (0)编辑 收藏

TOJ 3428. Fibonacci(Fibonacci数列的一个规律)

题意大概是给一组数M,N,求出第M个末位有N个0的Fibonacci数列是第几项。
乍一看,吓我一跳,结果在2^31内,大的惊人。后来拿一个程序(正好是TOJ的一道题,求1000位内的Fibonacci数列)暴力了下,好家伙,有规律的。
第一个末位有1个0的是第15项,第二项第30…然后看末位有2个0的,第一个是150项,第二个第300项。然后很高兴了写了个程序,WA...
有点晕,又暴力了下,加大范围,发现第一个末位3个0的不是1500项,而是750项。无奈了,好奇怪。于是猜只有这一个特例,依然WA。最后请教了个
学长,他说他也是猜的,不过后边的确实都是10倍了,就那一个特例。
接下来其实过程异常艰辛,不过最终思路很清晰,也AC了。
--------------------------------------------------------我是低调的分割线-------------------------------------------------------------------------------------
大概是这样分布的:
15             30            45     ...       150            165              180               195      ...          300        ...          750          ...          1500            ...           7500
第1个0       第2个0         第3个0               第1个00          第10个0              第11个0               第12个0                  第2个00                     第1个000                                                                 第1个0000     
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   

所以可以看到,不能直接按间隔算,因为比如150.,它算2个0,而不是第10个1个0。
又不能枚举,一定会超时(确实超了)
所以可以先按照没有重叠算,然后加上重叠的,重叠的只算下一个就好,因为再后边的也就都包括了。
算重叠的部分要把特殊的2拿出来。倍数是5就是 4  1  4  1  4  1这样分布,10的话就是 9  1  9  1  9  1  9  1  9  1,所以按照这样算,
比如要求第14个末位有2个0的,14%4!=0 ,14/4=3,所以重叠了3次。又比如20, 20%4==0,20/4-1=4,重叠4次。
Code:
 1 #include<stdio.h>
 2 int main(void)
 3 {
 4     int a[18]={0,15,150,750,7500,75000,750000,7500000,75000000,750000000};         //保存第一个连续1个0,2个0的第一个
 5     int i,j,k,m,n,cas,key;
 6     scanf("%d",&cas);
 7     while(cas--){
 8         scanf("%d%d",&n,&m);
 9         key=m*a[n];
10         if(n==2){
11             if(m%4!=0) key+=(m/4)*a[n];
12             else       key+=(m/4-1)*a[n];
13         }
14         else{
15             if(m%9!=0) key+=(m/9)*a[n];
16             else       key+=(m/9-1)*a[n];
17         }
18         printf("%d\n",key);
19     }
20 }

posted @ 2010-04-25 22:50 M.J 阅读(1880) | 评论 (2)编辑 收藏

TOJ 1593. URLs(字符串处理)

一个不是很难但是很麻烦的字符串处理问题。我记得在上学期就看过这个题,觉得太麻烦就没做。
今天终于搞定它了,而且我觉得代码在AC里也算短的了。
大意是给一个域名,然后找到它的什么协议,一级域名之类的。
Samble Input :
3
ftp://acm.baylor.edu:1234/pub/staff/mr-p
http://www.informatik.uni-ulm.de/acm
gopher://veryold.edu
Sample Output:

URL #1
Protocol = ftp
Host     = acm.baylor.edu
Port     = 1234
Path     = pub/staff/mr-p
URL #2
Protocol = http
Host     = www.informatik.uni-ulm.de
Port     = <default>
Path     = acm
URL #3
Protocol = gopher
Host     = veryold.edu
Port     = <default>
Path     = <default>
下面是代码:
 1 #include<iostream>
 2 #include<string>
 3 using namespace std;
 4 int main()
 5 {
 6     int i,j,k,m,n,len,key;
 7     string a,a1,a2,a3,a4;
 8     cin>>n;
 9     for(j=1;j<=n;j++){
10         cin>>a;
11         a1=a2=a3=a4="<default>";        //事先将所有字符串标记为" default "
12         len=a.length();
13         for(i=0;i<len;i++)
14             if(a[i]==':'){              //一旦遇到':'就跳出
15                 key=i;
16                 a1=a.substr(0,key);      // a1是协议名称
17                 break;
18             }
19         for(i=key+3;i<len;i++){
20             if(a[i]==':'||a[i]=='/')      //二级域名遇到':' 或者'/' 就停止
21                 break;
22             else
23                 continue;
24         }
25         if(key+3<len)
26         a2=a.substr(key+3,i-key-3);         
27         key=i; m=1;
28         for(i=key;i<len;i++){            //k 用来表示起始的位置
29             if(isdigit(a[i])){
30                 if(m){ k=i;m=0; } 
31                 continue;
32             }
33             else if(a[i]=='/')           //遇到'/'跳出
34                 break;
35         }                               // 如果存在三级域名,则赋值
36         if(i!=key)
37             a3=a.substr(k,i-k);
38         key=i+1;
39         if(key<len)a4=a.substr(key,len-key);    //剩下的是a4
40         cout<<"URL #"<<j<<endl;
41         cout<<"Protocol = "<<a1<<endl<<"Host     = "<<a2<<endl<<"Port     = "<<a3<<endl<<"Path     = "<<a4<<endl;
42         cout<<endl;
43     }
44 
45 }

posted @ 2010-04-25 14:04 M.J 阅读(168) | 评论 (0)编辑 收藏

POJ The Suspects(并查集)

又是一个并查集,题意大概是N个学生,学生0是SARS疑似,学生分为M组,一个学生可以属于不同组,只要和疑似学生在一组,自己也就成了疑似,问最后又多少学生是疑似病例。
Code:

 1 #include<stdio.h>
 2 #define MAX 30002
 3 int m,n;
 4 struct type
 5 {
 6     int father,v;
 7 }a[MAX];
 8 void initial(int n)
 9 {
10     int i;
11     for(i=0;i<n;i++){
12         a[i].father=i;
13         a[i].v=1;
14     }
15 }
16 int find(int n)
17 {
18     if(a[n].father!=n)
19         return find(a[n].father);
20     return n;
21 }
22 void Union(int root1,int root2)
23 {
24     int t1,t2;
25     t1=find(root1);
26     t2=find(root2);
27     if(t1==t2) return ;
28     if(t1!=t2){
29         if(a[t1].v<a[t2].v){
30             a[t1].father=t2;
31             a[t2].v+=a[t1].v;
32         }
33         else{
34             a[t2].father=t1;
35             a[t1].v+=a[t2].v;
36         }
37     }
38 }
39 int main()
40 {
41     int cas,i,j,k,p,q,N,M;
42     while(scanf("%d%d",&N,&M)!=EOF){
43         if(N==0&&M==0break;
44         initial(N);
45         for(i=1;i<=M;i++){
46             scanf("%d",&k);
47             scanf("%d",&p);
48             for(j=2;j<=k;j++){
49                 scanf("%d",&q);
50                 Union(p,q);
51             }
52         }
53         k=find(0);
54         printf("%d\n",a[k].v);
55     }
56     
57 
58 }

posted @ 2010-04-24 15:06 M.J 阅读(152) | 评论 (0)编辑 收藏

仅列出标题
共4页: 1 2 3 4