随笔:78 文章:7 评论:38 引用:0
C++博客 首页 发新随笔
发新文章 联系 聚合管理

一直觉得这个算法很神奇,昨天用到了,发现效果很好,速度果然很快!
int Montgomery(int a, int p, int m)
{
    
if(p==0return 1;
    
int r=a%m;
    
int k=1;
    
while(p>1){
        
if(p&1!=0){
            k
=(k*r)%m;
        }
        r
=(r*r)%m;
        p
/=2;
    }
    
return (r*k)%m;
}


posted @ 2009-08-12 11:49 未央 阅读(381) | 评论 (0)编辑 收藏
 
hdu 1811
题目大意:
    有n个点,m个序关系,关系只有三种表示方式:a < b , a > b , a = b,问根据给定的关系能否将n个点排成有序,能输出OK,若两点之间出现 a < b 且 b < a 的情况,则输出CONFLICT,若出现某些点间的关系不确定,则输出UNCERTAIN,若后两者同时存在,则优先输出CONFLICT。
题目分析:
    由于存在 a = b 的情况,所以需要用并查集,将所有相等的点进行缩点,然后进行拓扑排序,注意!优先输出CONFLICT。

#include<stdio.h>
#include
<string.h>
#include
<vector>
#define N 10010
using namespace std;
vector
<int>g[N];
int rank[N], f[N], m,n,num[N], save[20005][2], q[N];
int find(int x)//并查集的查找函数
{
    
if(f[x]==x) return x;
    
else return f[x]=find(f[x]); //路径压缩,而且这样写对汇编源码有优化,不容易因递归层数太多出现栈溢出,但仅是不易!
}
void Union(int x, int y)//并查集的合并操作
{
    
int a=find(x);
    
int b=find(y);
    
if(a!=b){
        
if(rank[a]<rank[b])      //通过判断两个集合的大小,将小集合并入大集合,减少递归层数,算是个优化
            f[a]
=b, rank[b]+=rank[a];
        
else
            f[b]
=a, rank[a]+=rank[b];
    }
}
int main()
{
    
int i,j,k,a,b,ans,tmp,x,y,tim;
    
char s[5];
    
while(scanf("%d %d",&n,&m)!=EOF){
        
for(i=0; i<=n; i++){
            f[i]
=i;
            g[i].clear();
            rank[i]
=1;
        }
        memset(num, 
0sizeof(num));
        k
=0;
        
for(i=0; i<m; i++){
            scanf(
"%d %s %d",&a, s, &b);
            
if(s[0]!='='){
                
if(s[0]=='>'){
                    tmp
=a;
                    a
=b;
                    b
=tmp;
                }
                save[k][
0]=a, save[k++][1]=b;
            }
            
else if(s[0]=='='){
                Union(a, b);
            }
        }
        
for(i=0; i<k; i++){
            x
=find(save[i][0]);
            y
=find(save[i][1]);
            g[x].push_back(y);
            num[y]
++;
        }
        ans
=0;
        
int head=0, tail=0;             //从这里开始拓扑排序,用队列做保险啊,直接写的话很容易错
        k
=0;
        
for(i=0; i<n; i++)
            
if(num[i]==0 && find(i)==i){ //找到第一轮入度(num[])为零的点入队。
                q[tail
++]=i;
                k
++;
            }
        
if(k==0)
            ans
=2;
        
else{
            
if(k>1) ans=1;  //本题要求
            
while(head<tail){                    //排序过程
                x
=q[head++]; num[x]=-1; k=0;
                
for(i=0; i<g[x].size(); i++){
                    y
=g[x][i];
                    num[y]
--;
                    
if(num[y]==0)
                        q[tail
++]=y, k++;
                }
                
if(k>1) ans=1//本题要求
            }
            
for(i=0; i<n; i++//本题要求
                if(num[i]>0){
                    ans
=2;
                    
break;
                }
        }
        
if(ans==0)
            printf(
"OK\n");
        
else if(ans==1)
            printf(
"UNCERTAIN\n");
        
else if(ans==2)
            printf(
"CONFLICT\n");
    }

    
return 0;
}

posted @ 2009-08-08 10:43 未央 阅读(467) | 评论 (0)编辑 收藏
 
1. Dijkstra算法
   这个算法和prime求最小生成树特别像,都是找到最小边,把点加进来,然后用新加的点更新其他没有被加进来的点。
   1.
      
#define N 1002
   
2.
      
#define MAX 99999
   
3.
      
int edges[N][N],d[N],n;
   
4.
       
   
5.
      
void dijkstra(int v)
   
6.
      {
   
7.
              
int i,j;
   
8.
              
bool s[N]={false};
   
9.
              
for(i=1;i<=n;i++)
  
10.
                      d[i]
=edges[v][i];
  
11.
              d[v]
=0;s[v]=true;
  
12.
              
for(i=1;i<n;i++)
  
13.
              {
  
14.
                      
int temp=MAX;
  
15.
                      
int u=v;
  
16.
                      
for(j=1;j<=n;j++)
  
17.
                              
if((!s[j])&&(d[j]<temp))
  
18.
                              {
  
19.
                                      u
=j;
  
20.
                                      temp
=d[j];
  
21.
                              }
  
22.
                              s[u]
=true;
  
23.
                              
for(j=1;j<=n;j++)
  
24.
                                      
if((!s[j])&&(edges[u][j]<MAX)&&(d[u]+edges[u][j])<d[j])
  
25.
                                              d[j]
=d[u]+edges[u][j];
  
26.
              }
  
27.
       
  
28.
      }

2. SPFA算法 (shortest path faster algorithm)
    不断维护一个队列,如果队列里的点,使得其他点的最短路得到松弛,则这个点还有可能使另外的点松弛,所以如果这个点不在队列里,就把它入队。
    很多时候,给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。 此算法时间复杂度为O(2*E),E为边数。
 //pku1860 
    #include<stdio.h>
    #include
<string.h>
    #include
<vector>
    
#define N 120
    
using namespace std;
    
struct Point
    {
        
int id;
        
double r, c;
    };
    vector
<Point> p[N];
    
int q[N],n,m,S,visit[N];
    
double V,dist[N];
    
int spfa()
    {
        memset(visit, 
0sizeof(visit));
        
int i,j,head=0,tail=1,x;
        
for(i=1; i<=n ;i++)
            dist[i]
=0;    //此题是求换得的货币最多,所以初值赋0;
                          
//若求最短路,初值应赋为无穷大
        if(V<=0return 0;
        q[
0]=S;
        dist[S]
=V;        //S为源,若求最短路,则dist[S]=0;
        visit[S]=1;
        
while(head!=tail){ // Attention!!!由于对队列长度取模了,所以head<tail不一定成立,应改为head!=tail
            x=q[head];
            visit[x]
=0;
            head
=(head+1)%N;
            
for(i=0; i<p[x].size(); i++){

                j
=p[x][i].id;
                
if(dist[j]<(dist[x]-p[x][i].c)*p[x][i].r){
                    dist[j]
=(dist[x]-p[x][i].c)*p[x][i].r;
                    
if(!visit[j]){
                        q[tail]
=j;
                        tail
=(tail+1)%N;
                        visit[j]
=1//若如果j点的最短路径估计值有所调整,
                                    
// 且j点不在当前的队列中,就将j点放入队尾
                    }
                }
            }
            
if(dist[S]>V) return 1;
        }
        
return 0;
    }
    
int main()
    {
        
int i,j,a,b;
        
double rab, cab, rba, cba;
        Point p1, p2;
        
while(scanf("%d %d %d %lf",&n, &m, &S, &V)!=EOF){
            
for(i=1; i<=n; i++)
                p[i].clear();
        
for(i=0; i<m; i++){
            scanf(
"%d %d %lf %lf %lf %lf",&a, &b, &rab, &cab, &rba, &cba);
            p1.id
=b; p1.r=rab; p1.c=cab;
            p2.id
=a; p2.r=rba; p2.c=cba;
            p[a].push_back(p1);
            p[b].push_back(p2);
        }
        j
=spfa();
        
if(j)
            printf(
"YES\n");
        
else
            printf(
"NO\n");
        }
        
return 0;
    }


posted @ 2009-07-30 22:44 未央 阅读(322) | 评论 (0)编辑 收藏
 
第一次接触字典树的实现,先看到了一个指针实现的模板,觉得很好理解,用着也方便,先收集过来 :)

//字典树用来查询有公共前缀的单词有多少个,插入和查询的时间复杂度均为O(n)

#include<iostream>
#include
<cstring>
#define N 300 //有N个单词
#define M 1000000//有M次查询
#define kind 26//26个英文字母
using namespace std;
struct Treenode
{
    
int count;
    Treenode 
*next[kind];
    Treenode(){
        
for(int i=0; i<kind; i++)
            next[i]
=NULL;
        count
=1;
    }
};
void insert(Treenode *&root, char *word)
{
    
int i=0,j,l=strlen(word),branch;
    Treenode 
*location=root;
    
if(location==NULL){
        location
=new Treenode();
        root
=location;
    }

    
for(i=0; i<l; i++){
        branch
=word[i]-'a';
        
if(location->next[branch])
            location
->next[branch]->count++;
        
else
            location
->next[branch]=new Treenode();
        location
=location->next[branch];
    }
}
int search(Treenode *&root, char *word)
{
    
int i, ans=0, l=strlen(word),branch;
    Treenode 
*location=root;
    
if(location==NULL) return 0;
    
for(i=0; i<l; i++){
        branch
=word[i]-'a';
        
if(!location->next[branch])
            
return 0;

        location
=location->next[branch];
        ans
=location->count;
    }
    
return ans;
}

int main()
{
    
int i,j,n,m;
    
char word[50];
    Treenode 
*root=NULL;
    scanf(
"%d"&n);
    
for(i=0; i<n; i++){
        scanf(
"%s",word);
        insert(root, word);
    }
    scanf(
"%d",&m);
    
for(i=0; i<m; i++){
        scanf(
"%s",word);
        printf(
"%d\n",search(root, word));
    }

    
return 0;
}

posted @ 2009-07-30 20:22 未央 阅读(456) | 评论 (0)编辑 收藏
 

<!--[if !supportLists]-->一、<!--[endif]-->网络流

<!--[if !supportLists]-->1.       <!--[endif]-->最大流:bfs

算法模板:

//1是源,point是汇

#include<stdio.h>
#include<string.h>
#include<queue>
#define N 870
using namespace std;
int M=999999;
int g[N][N], pre[N],point, edge, ans=0;
bool visit[N];
void update(int minf)
{
   int i=point;
   ans+=minf;
   while(pre[i]!=0){
     g[pre[i]][i]-=minf;
     g[i][pre[i]]+=minf;
     i=pre[i];
   }
}
void bfs()
{
    int i,j;
    while(1){
    queue<int> q;
    bool visit[N]={false};
    int minflow[N];
    memset(pre, 0, sizeof(pre));
    visit[1]=true;
    minflow[1]=M;
    q.push(1);
    while(!q.empty()){
    j=q.front(); q.pop();
    for(i=1; i<=point; i++)
       if(visit[i]==false && g[j][i]>0){
       minflow[i]=minflow[j]<g[j][i]?minflow[j]:g[j][i];
       pre[i]=j;
       visit[i]=true;
       q.push(i);
    }
    if(pre[point]>0) break;
  }
  if(pre[point]>0) update(minflow[point]);
  else
    break;
 }
}
int cal(char s)
{
   if(s<'Z' && s>='A')
      return s-'A'+1;
   else if(s<='z' && s>='a')
      return s-'a'+26;
   else if(s=='Z')

   return 52;
}
int main()
{
 int i,j,k,x,y,c,n;
 char a[3],b[3];
 scanf("%d",&n);
 point=52;
 for(i=0; i<n; i++){
  scanf("%1s%1s%d",&a[0], &b[0], &c);
  x=cal(a[0]); y=cal(b[0]);
  g[x][y]+=c;
 }
 bfs();
 printf("%d\n",ans);

 return 0;
}

 

2 匈牙利算法 二分匹配

这种题目的难度在于建立模型,算法写起来很简洁,还是增广路

//pku1325
#include
<stdio.h>
#include
<string.h>
#define N 120
int g[N][N], linked[N];
bool visit[N],n,m;
bool input()
{
    
int i,j,k,x,y;
    scanf(
"%d",&n);
    
if(n==0return false;
    scanf(
"%d %d",&m, &k);
    memset(g,
0sizeof(g));
    memset(linked, 
-1sizeof(linked));
    
for(i=0; i<k; i++){
        scanf(
"%d %d %d",&j, &x, &y);
        if(x*y)

           
g[x][y]=1;
    }
    
return true;
}
bool find(int x)
{
    
int i,j,k;
    
for(i=0; i<m; i++//这里标号从零开始
        if(!visit[i] && g[x][i]){
            visit[i]
=1;
            
if(linked[i]==-1 || find(linked[i])){
                linked[i]
=x;
                
return true;
            }
        }
    
return false;
}
int main()
{
    
int i, ans;
    
while(input())
    {
        ans
=0;
        
for(i=0; i<n; i++){
           
memset(visit, 0sizeof(visit));
            if(find(i))
                ans
++;
        }
        printf(
"%d\n", ans);
    }
    
return 0;
}

 

posted @ 2009-07-29 10:51 未央 阅读(400) | 评论 (0)编辑 收藏
 
The Balance
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 930 Accepted: 384

Description

Ms. Iyo Kiffa-Australis has a balance and only two kinds of weights to measure a dose of medicine. For example, to measure 200mg of aspirin using 300mg weights and 700mg weights, she can put one 700mg weight on the side of the medicine and three 300mg weights on the opposite side (Figure 1). Although she could put four 300mg weights on the medicine side and two 700mg weights on the other (Figure 2), she would not choose this solution because it is less convenient to use more weights.
You are asked to help her by calculating how many weights are required.

Input

The input is a sequence of datasets. A dataset is a line containing three positive integers a, b, and d separated by a space. The following relations hold: a != b, a <= 10000, b <= 10000, and d <= 50000. You may assume that it is possible to measure d mg using a combination of a mg and b mg weights. In other words, you need not consider "no solution" cases.
The end of the input is indicated by a line containing three zeros separated by a space. It is not a dataset.

Output

The output should be composed of lines, each corresponding to an input dataset (a, b, d). An output line should contain two nonnegative integers x and y separated by a space. They should satisfy the following three conditions.
  • You can measure dmg using x many amg weights and y many bmg weights.
  • The total number of weights (x + y) is the smallest among those pairs of nonnegative integers satisfying the previous condition.
  • The total mass of weights (ax + by) is the smallest among those pairs of nonnegative integers satisfying the previous two conditions.

No extra characters (e.g. extra spaces) should appear in the output.

Sample Input

700 300 200
500 200 300
500 200 500
275 110 330
275 110 385
648 375 4002
3 1 10000
0 0 0

Sample Output

1 3
1 1
1 0
0 3
1 1
49 74
3333 1

        怎么评价这道题呢,会做了,觉得这题挺水的,但是自己做了一下午,先是TLE后是WA,郁闷的不行,思维啊思维,做竞赛考思维啊!
题目大意:
给定a,b两种药品的重量,用他们的组合来测量第三种重量为d的药品,标准:
1.假设取x个重为a的药品,取y个重为b的药品;
2.在满足以上情况下,使得x+y最小;
3.在满足以上情况下,使得ax + by最小。
求x和y的值。(x和y均为正整数)

思路:
有三种情况:
ax+by=d;(a,b均在左盘)
ax-by=d;(a在左盘,b和d在右盘)
-ax+by=d;(b在左盘,a和d在右盘)
枚举a,求满足条件的解。

代码:
#include<iostream>
#include
<cmath>
using namespace std;
int main()
{
    
int i,a,b,d,x,y,xx,yy;
    
int sum1,sum2;
    
while(cin>>a>>b>>d)
    
{
        
if(a==0 && b==0 && d==0)break;
        
int min1=9000000,min2=9000000;
        
int t=0;
        xx
=0;yy=0;
        
for(i=0; ; i++){
            
if((d-a*i)%b==0)//ax+by=d 和 ax-by=d 两种情况,用绝对值表示,所以合写成一个if 
            {
                yy
=abs((d-a*i)/b);
                sum1
=i+yy;
                sum2
=a*i+b*yy;
                
if(sum1<min1)
                    min1
=sum1,min2=sum2,x=i,y=yy;
                
else if(sum1==min1 && sum2<min2)
                    min1
=sum1,min2=sum2,x=i,y=yy;
                
if(i>min1 || i*a>min2)//如果x的值比x+y的值都大或者a*x比a*x+b*y 的值都大了就跳出 
                    break;
            }

            
int l=i*a+d;
            
if(l>0 && l%b==0)//-ax+by=d的情况 
            {
                yy
=l/b;    
                sum1
=i+yy;
                sum2
=a*i+b*yy;
                
if(sum1<min1)
                    min1
=sum1,min2=sum2,x=i,y=yy;
                
else if(sum1==min1 && sum2<min2)
                    min1
=sum1,min2=sum2,x=i,y=yy;
                
if(i>min1 || i*a>min2)//如果x的值比x+y的值都大或者a*x比a*x+b*y 的值都大了就跳出
                    break;
                
            }

        }


        cout
<<x<<" "<<y<<endl;

    }


return 0;
}



         
posted @ 2008-07-20 09:53 未央 阅读(665) | 评论 (0)编辑 收藏
 

Rectangle Cutting


Time Limit: 1.0 Seconds   Memory Limit: 65536K



In the small historical village of Basinia, there is a popular activity in wedding ceremonies called rectangle cutting. During this activity, each close relative of the bride comes and cuts a rectangle in the wedding cake (but does not take a piece). The cake has a rectangular shape. The problem is to count how many pieces are in the cake after rectangle-cutting.

For example, in the following figure, the cake size is 3×5, and three people have made rectangular cuts in it. As a result, the cake is cut into six pieces.

Each rectangular cut is specified by the (x, y) coordinates of its two opposite corners. The input for the above figure can be found in the first sample input. As there are large families in Basinia, the number of pieces may be large and we need a computer program to compute it.

Input

The input contains several test cases. Each test has several lines. The first line has two integers w (1 ≤ w ≤ 20) and h (1 ≤ h ≤ 20) which are the width and height of the cake. The second line contains a single integer n (0 ≤ n ≤ 50) which is the number of people who cut rectangles in the cake. After this, there are n lines each containing the integers x1, y1, x2, y2 which are the coordinates of two opposite corners of the cut. You may assume 0 ≤ x1, x2w and 0 ≤ y1, y2h. The last line of the input is a line containing two zeros.

Output

For each test case, write the number of pieces the cake is cut into.

Sample Input

3 5
3
1 1 3 2
4 0 2 3
4 0 5 1
6 6
2
2 0 5 3
3 1 4 2
0 0

Sample Output

6
3
题目大意:
    给定一个w*h的矩形,在这个矩形里切小矩形,最后计算并输出封闭图形的个数
思路:
   把矩形看作w*h个小方块,第n次切割,就在所切的矩形的方块上标记数字2^n,如果重复切到同一个方块就把
标记值累加,这样标记完后再深搜,就得到封闭图形个数了。(标记为2^n,是ht同学的思想,很巧妙,但只能使用
于数据量比较小的情况)。同时此题应注意w 和 h 的顺序,我在这里耽误了好久,还wa了一次。
代码:
Source Code

Problem: 
3338  User: wic 
Memory: 272K  Time: 0MS 
Language: C
++  Result: Accepted 

Source Code 
#include
<iostream>
using namespace std;
int a[25][25];
int mark=-1,k;
int  w,h;
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int power(int a, int b)//pow的返回值类型不是int,于是自己写了一个函数
{
    
int ans=1;
    
while(b--)
        ans
*=a;
return ans;

}

bool inside(int x, int y)
{
    
if(x<=&& x>0 && y<=&& y>0)
        
return true;
    
else
        
return false;
}


void dfs(int x, int y)//自己写的深搜,嘿嘿
{
    
for(int i=0; i<4; i++){
        
int xx=x+dir[i][0];
        
int yy=y+dir[i][1];
        
if(inside(xx,yy) && a[yy][xx]!=mark && a[yy][xx]==k){
            a[yy][xx]
=mark;
            dfs(xx,yy);
        }

    }

}

int main()
{
    
int i,j,n,x1,y1,x2,y2,maxx,maxy,minx,miny,m;
    
while(cin>>w>>&& w && h){
        memset(a, 
0sizeof(a));
        cin
>>n;
        k
=0;
        
int c=0;
        
int count=0;
        
while(n--){
            cin
>>x1>>y1>>x2>>y2;
            maxx
=(x1>=x2)?x1:x2;
            minx
=(x1<=x2)?x1:x2;
            maxy
=(y1>=y2)?y1:y2;
            miny
=(y1<=y2)?y1:y2;
            m
=power(2,c);
        
            
for(i=miny+1; i<=maxy; i++)
                
for(j=minx+1; j<=maxx; j++)
                    a[i][j]
+=m;
    
    
        c
++;
        }

        k
=c;
        m
=power(2,k);
        
for(k=0; k<m; k++){
            
for(i=1; i<=w;  i++)
                
for(j=1; j<=h; j++)
                    
if(a[i][j]!=mark&&a[i][j]==k)
                    
{    dfs(j,i); count++;}
                    
        }

        cout
<<count<<endl;
    }



return 0;
}

 
posted @ 2008-07-18 23:22 未央 阅读(1255) | 评论 (2)编辑 收藏
 
     摘要:         这题初看起来被吓到了,以为要写成运算符重载,后来发现其实很水,呵呵(但是某人虽然在poj过了,但是却在tojWA了5次,实在不解,呵呵)思路:接入字符串,去掉空格,从头到尾扫,遇到字母就检测它的前后两位有没有++(--)如果有进行处理,然后看它的后(前)面第3为是+(-)就加(减)到和sum里;用一个三维数组v[26][3...  阅读全文
posted @ 2008-07-18 23:06 未央 阅读(956) | 评论 (1)编辑 收藏
仅列出标题
共8页: 1 2 3 4 5 6 7 8 
CALENDER
<2009年8月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
303112345

常用链接

留言簿(6)

随笔档案

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜


Powered By: 博客园
模板提供沪江博客