一直覺(jué)得這個(gè)算法很神奇,昨天用到了,發(fā)現(xiàn)效果很好,速度果然很快!
int Montgomery(int a, int p, int m) { if(p==0) return 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; }
hdu 1811 題目大意: 有n個(gè)點(diǎn),m個(gè)序關(guān)系,關(guān)系只有三種表示方式:a < b , a > b , a = b,問(wèn)根據(jù)給定的關(guān)系能否將n個(gè)點(diǎn)排成有序,能輸出OK,若兩點(diǎn)之間出現(xiàn) a < b 且 b < a 的情況,則輸出CONFLICT,若出現(xiàn)某些點(diǎn)間的關(guān)系不確定,則輸出UNCERTAIN,若后兩者同時(shí)存在,則優(yōu)先輸出CONFLICT。 題目分析: 由于存在 a = b 的情況,所以需要用并查集,將所有相等的點(diǎn)進(jìn)行縮點(diǎn),然后進(jìn)行拓?fù)渑判颍⒁猓?yōu)先輸出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)//并查集的查找函數(shù) { if(f[x]==x) return x; else return f[x]=find(f[x]); //路徑壓縮,而且這樣寫對(duì)匯編源碼有優(yōu)化,不容易因遞歸層數(shù)太多出現(xiàn)棧溢出,但僅是不易! } void Union(int x, int y)//并查集的合并操作 { int a=find(x); int b=find(y); if(a!=b){ if(rank[a]<rank[b]) //通過(guò)判斷兩個(gè)集合的大小,將小集合并入大集合,減少遞歸層數(shù),算是個(gè)優(yōu)化 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, 0, sizeof(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āi)始拓?fù)渑判颍藐?duì)列做保險(xiǎn)啊,直接寫的話很容易錯(cuò) k=0; for(i=0; i<n; i++) if(num[i]==0 && find(i)==i){ //找到第一輪入度(num[])為零的點(diǎn)入隊(duì)。 q[tail++]=i; k++; } if(k==0) ans=2; else{ if(k>1) ans=1; //本題要求 while(head<tail){ //排序過(guò)程 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; }
1. Dijkstra算法 這個(gè)算法和prime求最小生成樹(shù)特別像,都是找到最小邊,把點(diǎn)加進(jìn)來(lái),然后用新加的點(diǎn)更新其他沒(méi)有被加進(jìn)來(lái)的點(diǎn)。
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) 不斷維護(hù)一個(gè)隊(duì)列,如果隊(duì)列里的點(diǎn),使得其他點(diǎn)的最短路得到松弛,則這個(gè)點(diǎn)還有可能使另外的點(diǎn)松弛,所以如果這個(gè)點(diǎn)不在隊(duì)列里,就把它入隊(duì)。 很多時(shí)候,給定的圖存在負(fù)權(quán)邊,這時(shí)類似Dijkstra等算法便沒(méi)有了用武之地,而B(niǎo)ellman-Ford算法的復(fù)雜度又過(guò)高,SPFA算法便派上用場(chǎng)了。 此算法時(shí)間復(fù)雜度為O(2*E),E為邊數(shù)。
//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, 0, sizeof(visit)); int i,j,head=0,tail=1,x; for(i=1; i<=n ;i++) dist[i]=0; //此題是求換得的貨幣最多,所以初值賦0; //若求最短路,初值應(yīng)賦為無(wú)窮大 if(V<=0) return 0; q[0]=S; dist[S]=V; //S為源,若求最短路,則dist[S]=0; visit[S]=1; while(head!=tail){ // Attention!!!由于對(duì)隊(duì)列長(zhǎng)度取模了,所以head<tail不一定成立,應(yīng)改為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點(diǎn)的最短路徑估計(jì)值有所調(diào)整, // 且j點(diǎn)不在當(dāng)前的隊(duì)列中,就將j點(diǎn)放入隊(duì)尾 } } } 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; }
第一次接觸字典樹(shù)的實(shí)現(xiàn),先看到了一個(gè)指針實(shí)現(xiàn)的模板,覺(jué)得很好理解,用著也方便,先收集過(guò)來(lái) :) //字典樹(shù)用來(lái)查詢有公共前綴的單詞有多少個(gè),插入和查詢的時(shí)間復(fù)雜度均為O(n)
#include<iostream> #include<cstring> #define N 300 //有N個(gè)單詞 #define M 1000000//有M次查詢 #define kind 26//26個(gè)英文字母 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; }
<!--[if !supportLists]-->一、<!--[endif]-->網(wǎng)絡(luò)流
<!--[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 匈牙利算法 二分匹配
這種題目的難度在于建立模型,算法寫起來(lái)很簡(jiǎn)潔,還是增廣路
//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==0) return false; scanf("%d %d",&m, &k); memset(g, 0, sizeof(g)); memset(linked, -1, sizeof(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++) //這里標(biāo)號(hào)從零開(kā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, 0, sizeof(visit)); if(find(i)) ans++; } printf("%d\n", ans); } return 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
怎么評(píng)價(jià)這道題呢,會(huì)做了,覺(jué)得這題挺水的,但是自己做了一下午,先是TLE后是WA,郁悶的不行,思維啊思維,做競(jìng)賽考思維啊! 題目大意: 給定a,b兩種藥品的重量,用他們的組合來(lái)測(cè)量第三種重量為d的藥品,標(biāo)準(zhǔn): 1.假設(shè)取x個(gè)重為a的藥品,取y個(gè)重為b的藥品; 2.在滿足以上情況下,使得x+y最小; 3.在滿足以上情況下,使得ax + by最小。 求x和y的值。(x和y均為正整數(shù)) 思路: 有三種情況: 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 兩種情況,用絕對(duì)值表示,所以合寫成一個(gè)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;
}


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, x2 ≤ w and 0 ≤ y1, y2 ≤ h. 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
題目大意:
給定一個(gè)w*h的矩形,在這個(gè)矩形里切小矩形,最后計(jì)算并輸出封閉圖形的個(gè)數(shù)。
思路:
把矩形看作w*h個(gè)小方塊,第n次切割,就在所切的矩形的方塊上標(biāo)記數(shù)字2^n,如果重復(fù)切到同一個(gè)方塊就把
標(biāo)記值累加,這樣標(biāo)記完后再深搜,就得到封閉圖形個(gè)數(shù)了。(標(biāo)記為2^n,是ht同學(xué)的思想,很巧妙,但只能使用
于數(shù)據(jù)量比較小的情況)。同時(shí)此題應(yīng)注意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,于是自己寫了一個(gè)函數(shù)
  {
int ans=1;
while(b--)
ans*=a;
return ans;

}
bool inside(int x, int y)
  {
if(x<=h && x>0 && y<=w && 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>>h && w && h) {
memset(a, 0, sizeof(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;
}

摘要: 這題初看起來(lái)被嚇到了,以為要寫成運(yùn)算符重載,后來(lái)發(fā)現(xiàn)其實(shí)很水,呵呵(但是某人雖然在poj過(guò)了,但是卻在tojWA了5次,實(shí)在不解,呵呵)思路:接入字符串,去掉空格,從頭到尾掃,遇到字母就檢測(cè)它的前后兩位有沒(méi)有++(--)如果有進(jìn)行處理,然后看它的后(前)面第3為是+(-)就加(減)到和sum里;用一個(gè)三維數(shù)組v[26][3... 閱讀全文
|