dfs //http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3631 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[40]; int b[40]; int ans; int n, m; /* void dfs(int k, int sum) { if(ans == m)return; if(k == 0){ ans = max(sum, ans); return; } if(a[k] + sum <= m) { if(b[k] + sum <= m) { ans = max(ans, b[k] + sum); return; }else{ ans = max(ans, sum + a[k]); dfs(k-1, sum); dfs(k-1, sum + a[k]); } }else{ ans = max(ans, sum); dfs(k-1, sum); } } int main(){ while(~scanf("%d%d", &n, &m)) { for(int i = 1; i <= n; i ++) scanf("%d", a + i); sort(a+1, a +1+ n); //for(int i = 1; i <= n;i ++)printf("%d\n", a[i]); int count = 1; for(int i = 1; i <= n; i ++) if(a[i] <= m) a[count++] = a[i]; n = count-1; //printf("%d\n", n); //for(int i = 1; i <= n;i ++)printf("%d\n", a[i]); b[1] = a[1]; for(int i = 2; i <= n; i ++) b[i] = a[i] + b[i-1]; //for(int i = 1; i <= n;i ++)printf("%d\n", b[i]); ans = 0; dfs(n, 0); printf("%d\n", ans); } return 0; } */ void dfs(int id, int sum) { if(ans == m)return;//为什么少这一句会T ? if(sum > ans ) ans = sum; for(int i = id; i < n; i ++) { if(sum + a[i] <= m) dfs(i+1, sum + a[i]); } } int main() { while(~scanf("%d%d", &n, &m)) { int s = 0; for(int i = 0; i < n; i ++) { scanf("%d", a + i); s += a[i]; } if(s <= m) { printf("%d\n", s); continue; } //memset(vis, 0, sizeof(vis)); sort(a, a + n); ans = -1; dfs(0,0); if(ans == -1) puts("0"); else printf("%d\n", ans); } return 0; } bfs Matrix: struct point{ int x, y; int step; }; int dir[4][2] = { , 0, -1, 0, , 1, , -1 }; void bfs(point start){ queue < point > q; q.push(start); while(!q.empty()){ point tmp = q.front(); q.pop(); for(int i = 0; i < 4; i ++){ int x = tmp.x + dir[i][0]; int y = tmp.y + dir[i][1]; if(x < 0 || x >= n || y < 0 || y >= m) continue; if(vis[x][y] == 1) continue; if(map[x][y] == '#') continue; point now; now.x = x, now.y = y, now.step = tmp.step ++; q.push(now); } } } const int maxn = 50000 + 10; struct edge{ int to, w; edge * next; }*list[maxn]; void add_edge(int u, int v, int w){ edge *tmp = new edge; tmp->to = v; tmp->w = w; tmp->next = list[u]; list[u] = tmp; } void bfs(int start){ queue < int > q; q.push(start); while(!q.empty()){ int hd = q.front(); q.pop(); edge *tmp = list[hd]; while(tmp != NULL){ if(tmp->to @#$%^){ q.push(tmp->to); } tmp = tmp->next; } } } 背包: vodi zero_one_pack(int cost, int weight){ for(int i = v; i >= cost; i --){//v是最大值 dp[i] = max(dp[i], dp[i - cost] + weight); } } void complete_pack(int cost, int weight){ for(int i = cost; i <= v; i ++){ dp[i] = max(dp[i], dp[i - cost] + weight); } } void multipack(int cost, int weight, int amount){ if(amount * cost >= v){ complete_pack(cost, weight); return; } int k = 1; while( k < amount){ zero_one_pack(cost * k, weight * k); amount -= k; k <<= 1; } zero_one_pack(amount * cost, amount * weight); } AOV网络,Topsort #include<cstdio> #include<cstring> const int maxn = 50000 + 10; struct edge{ int to, w; edge * next; }*list[maxn]; void add_edge(int u, int v,int w){ edge *tmp = new edge; tmp->to = v; tmp->w = w; tmp->next = list[u]; list[u] = tmp; } int n, m; int ind[maxn];//入度 char output[100]; void topsort(){ int top = -1; edge *tmp; bool bcycle = false;//判断是否存在有向环 int pos = 0;//写入output数组的位置 for(int i = 0; i < n; i ++){//入度为0的顶点入栈 if(ind[i] == 0){ ind[i] = top; top = i; } } for(int i = 0; i < n; i ++){ if(top == -1){ bcycle = true; break; }else{ int j = top; top = ind[top]; pos += sprintf(output + pos , "%d ", j + 1); tmp = list[j]; while(tmp != NULL){ int k = tmp->to; if((-- ind[k]) == 0){ ind[k] = top; top = k; } tmp = tmp->next; } } } if(bcycle) puts("network has a cycle!"); else{ output[strlen(output) - 1] = 0; printf("%s\n", output); } } int main(){ while(~scanf("%d%d", &n ,&m)){ memset(list, 0, sizeof(list)); memset(ind, 0, sizeof(ind)); memset(output, 0, sizeof(output)); for(int i = 0; i < m; i ++){ int u, v; scanf("%d%d", &u, &v); u--; v--; ind[v] ++; add_edge(u, v, 0); } topsort(); for(int i = 0; i < n; i ++){ edge *tmp = list[i]; while(tmp != NULL){ list[i] = tmp->next; delete tmp; tmp = list[i]; } } } return 0; } /* 8 2 4 6 2 6 1 2 6 8 3 2 5 4 2 6 4 6 1 4 3 2 6 network has a cycle! */ //http://poj.org/problem?id=2585 #include<cstdio> #include<cstring> #include<string> using namespace std; string cover[4][4]; void init(){ /* for(int i = 0; i < 4; i ++){ for(int j = 0; j < 4; j ++) cover[i][j].erase(); } */ for(int k = 1; k <= 9; k ++){ int i = (k-1) / 3; int j = (k-1) % 3; cover[i][j] += char(k + '0'); cover[i+1][j] += char(k + '0'); cover[i][j+1] += char(k + '0'); cover[i+1][j+1] += char(k + '0'); } } int ind[10]; bool g[10][10]; int screen[5][5]; bool exist[10]; int t = 0; void calc(){ memset(ind, 0, sizeof (ind)); memset(g, 0, sizeof (g)); memset(exist, 0, sizeof (exist)); t = 0; for(int i = 0; i < 4; i ++){ for(int j = 0; j < 4; j ++){ int k; scanf("%d", &k); screen[i][j] = k; if(!exist[k]) t ++; exist[k] = true; } } } void build(){ for(int i = 0; i < 4; i ++){ for(int j = 0; j < 4; j ++){ for(int k = 0; k < cover[i][j].length(); k ++){ /* if( (g[screen[i][j]][cover[i][j][k]-'0'] == 0) && screen[i][j] != cover[i][j][k] - '0'){ g[screen[i][j]][cover[i][j][k]-'0'] = true; ind[cover[i][j][k] - '0'] ++; } */ int u = screen[i][j]; int v = cover[i][j][k]-48; if(g[u][v] == 0 && u != v){ g[u][v] = true; ind[v] ++; } } } } } bool check(){ /* for(int j = 0; j < t; j ++){ int i = 1; while( !exist[i] || ( i <= 9 && ind[i] >0)) i ++;//这个很好 if(i > 9)return false;//说明入度都大于0了,那么就存在环了 exist[i] = false; int k = i; for(i = 1; i <= 9; i++){ if(exist[i] && g[k][i]) ind[i] --; } } return true; */ // for(int i = 1; i <= 9; i ++)printf("++ %d %d\n", i, ind[i]); for(int i = 1; i <= 9; i ++){ for(int j = 1; j <= 9; j ++){ if(ind[j] == 0){ ind[j] = -1; for(int k = 1; k <= 9; k ++){ if(g[j][k] == false) continue; ind[k] --; } } } } //for(int i = 1; i <= 9; i ++)printf("-- %d %d\n", i, ind[i]); int flag = 0; for(int i = 1; i <= 9; i ++){ if(ind[i] != -1){ flag = 1; break; } } if(flag) return false; else return true; } int main(){ init(); char s[15]; while(~scanf("%s", s)){ if(strcmp(s, "ENDOFINPUT") == 0) break; calc(); build(); if(check()) puts("THESE WINDOWS ARE CLEAN"); else puts("THESE WINDOWS ARE BROKEN"); scanf("%s", s); } return 0; } #include<cstdio> #include<cstring> char map[2010][2010]; int ind[2010]; int vis[2010]; int main(){ int tcase; scanf("%d", &tcase); int z = 1; while(tcase --){ int n; scanf("%d", &n); memset(vis, -1, sizeof vis); for(int i = 0; i < n;i ++){ scanf("%s", map[i]); for(int j = 0; map[i][j]; j ++) if(map[i][j] == '1') ind[j] ++; } int flag = 0; for(int i = 0; i < n; i ++){ int j = 0; while(j < n && ind[j] != 0)//找到第一个入度为0的并且没有进入栈的点 j ++; if(j >= n){ flag = 1; break; } ind[j] --; for(int k = 0; map[j][k]; k ++){ if(map[j][k] == '1'){ ind[k] --; } } } printf("Case #%d: ", z++); if(flag) puts("Yes"); else puts("No"); } return 0; } AOE网络,最长路,关键路径 #include<cstdio> #include<cstring> const int maxn = 10000;//顶点个数最大值 const int maxm = 10000;//边数最大值 struct node{ int to, w, id;//边的另一个顶点,持续时间,活动序号 int next; }list1[maxn], list2[maxn]; int p1[maxm], p2[maxm];//入边表,出边表 int ind1[maxn], ind2[maxn];//入度, 出度 int Ee[maxn];//各事件的最早可能开始时间 int El[maxn];//各事件的最迟允许开始时间 int e[maxm];//各活动的最早可能开始时间 int l[maxm];//各活动的最迟允许开始时间 int n, m; void criticalpath(){ int top1 = -1; memset(Ee, 0, sizeof Ee); for(int i = 0; i < n; i ++){ if(ind1[i] == 0){ ind1[i] = top1; top1 = i; } } for(int i = 0; i < n; i ++){ if(top1 == -1){ printf("network has a cycle!\n"); return; } int j = top1; top1= ind1[top1]; for(int k = p1[j]; k != -1; k = list1[k].next){ int v = list1[k].to; if( -- ind1[v] == 0){ ind1[v] = top1; top1 = v; } if(Ee[j] + list1[k].w > Ee[v]) Ee[v] = Ee[j] + list1[k].w; } } int top2 = -1; for(int i = 0; i < n; i ++){ El[i] = Ee[n-1]; if(ind2[i] == 0){ ind2[i] = top2; top2 = i; } } for(int i = 0; i < n; i ++){ int j = top2; top2 = ind2[top2]; for(int k = p2[j]; k != -1; k = list2[k].next){ int v = list2[k].to; if( -- ind2[v] == 0){ ind2[v] = top2; top2 = v; } if( El[j] - list2[k].w < El[v]) El[v] = El[j] - list2[k].w; } } memset(e, 0, sizeof e); memset(l, 0, sizeof l); for(int i = 0; i < n;i ++){ for(int k = p1[i]; k != -1; k = list1[k].next){ //puts("Asdf"); int v = list1[k].to; int id = list1[k].id; e[id] = Ee[i]; l[id] = El[v] - list1[k].w; //printf("%d %d\n", e[id], l[id]); if(e[id] == l[id]) printf("a%d : %d->%d\n", id, i, v); } } } void init(){ memset(list1, 0, sizeof list1); memset(list2, 0, sizeof list2); memset(ind1, 0, sizeof ind1); memset(ind2, 0, sizeof ind2); memset(p1, -1, sizeof p1); memset(p2, -1, sizeof p2); } int main(){ init(); scanf("%d%d", &n, &m); int index1 = 0; int index2 = 0; for(int i = 0; i < m; i ++){ int u, v, w; scanf("%d%d%d", &u, &v, &w); ind1[v] ++; list1[index1].to = v; list1[index1].w = w; list1[index1].id = i + 1; list1[index1].next = p1[u]; p1[u] = index1 ++; ind2[u] ++; list2[index2].to = u; list2[index2].w = w; list2[index2].id = i + 1; list2[index2].next = p2[v]; p2[v] = index2 ++; } criticalpath(); return 0; } /* 6 4 5 1 1 2 9 7 4 2 4 a1 : 0->1 a4 : 1->4 a8 : 4->7 a7 : 4->6 a10 6->8 a11 : 7->8 */ 并查集,kruckal int pre[110]; struct edge{ int u,v,w; friend bool operator <(const edge &a, const edge &b){ return a.w < b.w; } }e[11000]; int find(int x){ int s;//查找位置 for(s = x; pre[s] >= 0; s = pre[s]); while(x != s){//压缩路径,使后续的查找操作加速 int t = pre[x]; pre[x] = s; x = t; } return s; } void Union(int x, int y){ int u = find(x); int v = find(y); if(u == v) return;//如果在同一棵树上 if(pre[u] > pre[v]){ pre[u] += pre[v]; pre[v] = u; }else{ pre[v] += pre[u]; pre[u] = v; } } void kruskal(){ int sumweight = 0;//生成树的权值 int num = 0;//已选用的边的数目 memset(pre, -1, sizeof pre);//初始化数组,重要!!! for(int i = 0; i < m; i ++){ int u = e[i].u; int v = e[i].v; if(find(u) != find(v)){ suweight += e[i].w; num ++; Union(u, v); } if(num >= n - 1) break; } printf("%d\n", sumweight); } //注意要先给边排序,按从小大到 Kruskal 和 prime #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int inf = 0x3fffffff; int pre[200]; struct edge{ int u, v, w; friend bool operator < (const edge &a, const edge &b){ return a.w < b.w; } }a[200]; int find(int x){ int s; for(s = x; pre[s] >= 0; s = pre[s]); while(s != x){ int t = pre[x]; pre[x] = s; x = t; } return s; } void Union(int x, int y){ int u = find(x); int v = find(y); if(u == v)return; if(pre[u] > pre[v]){ pre[u] += pre[v]; pre[v] = u; }else{ pre[v] += pre[u]; pre[u] = v; } } int e[200][200]; char op[3]; int n; int visit[200]; int dist[200]; int prim(){ memset(visit, 0, sizeof(visit)); for(int i = 0; i < n; i++){ dist[i] = e[0][i]; } dist[0] = 0; visit[0] = 1; //for(int i = 0; i < n; i++)printf("%d ",dist[i]);puts(""); int sum = 0; //puts("asdf"); for(int i = 0; i < n - 1; i++){ int min_num = inf; int v; for(int j = 0; j < n; j++){ if(!visit[j] && dist[j] < min_num){ min_num = dist[j]; v = j; } } //printf("-- %d %d\n", v, min_num); visit[v] = 1; sum += min_num; for(int j = 0; j < n; j++){ if(!visit[j] && e[v][j] != 0 && e[v][j] < dist[j]){ dist[j] = e[v][j]; } } } //for(int i = 0; i < n; i++)printf("%d ", dist[i]);puts(""); return sum; } int m; int kruskal(){ memset(pre, -1, sizeof(pre)); int num = 0; int sum = 0; for(int i = 0; i < m; i++){ int u = a[i].u; int v = a[i].v; if(find(u) != find(v)){ num ++; sum += a[i].w; Union(u,v); } if(num >= n - 1)break; } return sum; } int main(){ while(scanf("%d", &n), n){ int t; memset(e, 0 ,sizeof(e)); m = 0; for(int i = 0; i < n-1; i++){ scanf("%s%d", op, &t); int u = op[0] - 65; int tt; //puts("asdfsdf"); while(t--){ scanf("%s%d", op, &tt); int v = op[0] - 65; e[u][v] = e[v][u] = tt; a[m].u = u; a[m].v = v; a[m++].w = tt; } } sort(a, a+m); for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ if(e[i][j] == 0) e[i][j] = inf; } } //printf("%d\n", prim()); printf("%d\n", kruskal()); } return 0; } http://acm.hdu.edu.cn/showproblem.php?pid=4325 离散化 + unique + lower_bound #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 100000 + 10; int a[maxn], b[maxn], c[maxn]; int d[maxn<<2]; int e[maxn<<2]; int main(){ //freopen("1006.in", "r", stdin);freopen("out.out", "w", stdout); int tcase; scanf("%d", &tcase); int z = 1; while(tcase --){ int n, m; scanf("%d%d", &n, &m); int cnt = 0; for(int i = 0; i < n;i ++){ scanf("%d%d", a+i, b+i); d[cnt++] = a[i]; d[cnt++] = b[i]; } for(int i = 0; i < m; i ++){ scanf("%d", c+i); d[cnt++] = c[i]; } sort(d, d + cnt); int tmp = unique(d,d + cnt) - d; //printf("----------- %d\n", tmp); cnt = tmp; int count = 0; memset(e, 0, sizeof e); for(int i = 0; i < n;i ++){ int l = lower_bound(d, d+cnt, a[i]) - d; int r = lower_bound(d, d+cnt, b[i]) - d; for(int j = l; j <= r; j ++){ e[j] ++; } } printf("Case #%d:\n", z++); for(int i = 0; i < m; i ++){ int pos = lower_bound(d, d+cnt, c[i]) - d; printf("%d\n", e[pos]); } } return 0; } http://poj.org/problem?id=1679 # include <iostream> # include <cstdio> # include <algorithm> # include <cstring> using namespace std; //先求出最小生成树,然后删除这棵树上的每条边求MST,求的时候要判断是否是MST struct edge{ int u, v, w, f; friend bool operator < (const edge &a, const edge &b){ return a.w < b.w; } }e[100 * 100 + 10]; int pre[110]; int n, m; int find(int x){ int s; for(s = x; pre[s] >= 0; s = pre[s]); while(s != x){ int t = pre[x]; pre[x] = s; x = t; } return s; } void Union(int x, int y){ int u = find(x); int v = find(y); if(u == v) return;//如果在同一棵树上 if(pre[u] > pre[v]){ pre[u] += pre[v]; pre[v] = u; }else{ pre[v] += pre[u]; pre[u] = v; } } int kruskal(int f){ int w = 0; int num = 0; memset(pre, -1, sizeof pre); for(int i = 0; i < m; i ++){ if(e[i].f == 2) continue; int u = e[i].u; int v = e[i].v; if(find(u) != find(v)){ w += e[i].w; if(f)e[i].f = 1; num ++; Union(u, v); } if(num >= n - 1) break; } if(num == n-1) return w; else return -1;//说明没有找到MST } int main(){ int tcase; scanf("%d", &tcase); while(tcase --){ scanf("%d%d", &n, &m); for(int i = 0; i < m; i ++){ scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w); e[i].f = 0; } sort(e, e + m); int w = kruskal(1); int flag = 0; for(int i = 0; i < m; i ++){ if(e[i].f == 0)continue; e[i].f ++; int tmp = kruskal(0); e[i].f --; //printf("%d ---\n", tmp); if(tmp != -1 && tmp == w){ flag = 1; break; } } if(flag) puts("Not Unique!"); else printf("%d\n", w); } return 0; } /* //牛人做法,拿来当模板用 int const INF=1000000000; int const maxn=105; int mark[maxn],map[maxn][maxn],mst[maxn]; int n,m; void prim(){ int i,j,k,ans=0,min,v,flag=0; for (i=1;i<=n;i++){ mark[i]=0; mst[i]=map[1][i]; } mark[1]=1; for (i=1;i<n;i++){ min=INF; for (j=1;j<=n;j++){ if (!mark[j] && mst[j]<min){ min=mst[j]; v=j; } } k=0; //------------------------------ //如果要选的点到已选的点,还有一条边权值相同,就 NO 了 for (j=1;j<=n;j++){ if (mark[j] && min==map[v][j])k++; } if (k>1){flag=1;break;} //------------------------------ ans+=min; mark[v]=1; for (j=1;j<=n;j++){ if (!mark[j] && map[v][j]<mst[j])mst[j]=map[v][j]; } } if (flag)cout<<"Not Unique!"<<endl; else cout<<ans<<endl; } int main() { int cas,i,j,p,q,w; cin>>cas; while (cas--) { cin>>n>>m; for (i=1;i<=n;i++) for (j=1;j<=n;j++) map[i][j]=INF; while (m--) { cin>>p>>q>>w; map[q][p]=map[p][q]=w; } prim(); } return 0; } */ 树状数组 HDU1166敌兵布阵 #include<cstdio> #include<cstring> const int maxn = 50000 + 10; int a[maxn], c[maxn]; int n; inline int lowbit(int x){ return x&(-x); } inline void update(int pos, int x){ while(pos <= n){ c[pos] += x; pos += lowbit(pos); } } inline int query(int end){ int sum = 0; while(end > 0){ sum += c[end]; end -= lowbit(end); } return sum; } int main(){ int tcase; scanf("%d", &tcase); int z = 1; while(tcase --){ scanf("%d", &n); memset(a, 0, sizeof a); memset(c, 0, sizeof c); for(int i = 1; i <= n;i ++){ scanf("%d", a + i); update(i, a[i]); } printf("Case %d:\n", z++); char op[10]; while(scanf("%s", op) && op[0] != 'E'){ int i, j; scanf("%d%d", &i, &j); switch(op[0]){ case 'Q': printf("%d\n", query(j) - query(i - 1)); break; case 'A': update(i, j); a[i] += j; break; case 'S': update(i, -j); a[i] -= j; } } } return 0; } 最短路 邻接表: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=1000; //定义最大值即0x7fffffff const int inf=~0U>>1; int path[maxn];//保存路径 int visit[maxn];//标记是否访问 int dist[maxn];//保存距离,即结果 int shortest[maxn];//保存倒找的结点 //边的结构体 struct edge{ int to,w; edge*next; }*list[maxn]; int n,m; //按最短路长短排序 struct sort__{ int len; int num; //重载运算符 friend bool operator <(const sort__&a,const sort__&b){ if(a.len!=b.len)return a.len<b.len;else a.num<b.num; } }ans[maxn]; //加边 void add_edge(int u,int v,int w){ edge *tmp=new edge; tmp->to=v; tmp->w=w; tmp->next=list[u]; list[u]=tmp; } //dijkstra算法实现 void dijk(int u){ edge *tmp=list[u]; for(int i=1;i<=n;i++)dist[i]=inf; memset(visit,0,sizeof(visit)); memset(path,-1,sizeof(path)); while(tmp!=NULL){ int v=tmp->to; dist[v]=tmp->w; path[v]=u; tmp=tmp->next; } visit[u]=1; dist[u]=0; for(int i=1;i<n;i++){ int min=inf,uu=u; for(int j=1;j<=n;j++){ if(!visit[j] && dist[j]<min){ uu=j; min=dist[j]; } } visit[uu]=1; tmp=list[uu]; while(tmp!=NULL){ int v=tmp->to; if(!visit[v] && dist[uu]+tmp->w<dist[v]){ dist[v]=dist[uu]+tmp->w; path[v]=uu; } tmp=tmp->next; } } } //递归输出 void dfs(int i) { //if(i==-1)return; if(path[i]==i) return; dfs(path[i]); printf("%d--->",path[i]); } int main(){ //freopen("最短路.txt","r",stdin); while(~scanf("%d%d",&n,&m)){ memset(list,NULL,sizeof(list)); for(int i=0;i<m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); //无向图要加双向边 add_edge(u,v,w); add_edge(v,u,w); } dijk(1); //for(int i = 1; i <= n;i ++)printf("%d\n", path[i]); //保存信息然后排序 for(int i=1;i<=n;i++){ ans[i].num=i; ans[i].len=dist[i]; } sort(ans+1,ans+1+n); for(int i=2;i<=n;i++){ //printf("%d\n",dist[i]); printf("%d\n",ans[i].len); dfs(i); printf("%d\n",i); puts(""); /* //非递归输出 memset(shortest,0,sizeof(shortest)); int k=1; shortest[k]=ans[i].num; while(path[shortest[k]]!=-1){ k++; shortest[k]=path[shortest[k-1]]; } k++; shortest[k]=0; for(int j=k-1;j>1;j--){ printf("%d-->",shortest[j]); } printf("%d\n\n",shortest[1]); */ } } return 0; } 矩阵: const int maxn = 100;//顶点个数 const int inf = ~0U>>1; int visit[maxn];//标记 int dist[maxn];//记录从当前点开始最短路到各点的距离 int path[maxn];//记录路径 int g[maxn][maxn]; void dijk(int u){ for(int i = 0; i < n; i ++){ dist[i] = g[u][i]; visit[i] = 0; if( i != u && dist[i] < inf) path[i] = u; else path[i] = -1; } visit[u] = 1; dist[u] = 0; for(int i = 0; i < n - 1; i ++){//确定n-1条最短路径 int min_num = inf, v; for(int j = 0; j < n; j ++){ if(!visit[j] && dist[j] < min_num){ v = j; min_num = dist[j]; } } visit[v] = 1; for(int j = 0; j < n; j ++){ if(!visit[j] && g[v][j] < inf && dist[v] + g[v][j] < dist[j]){ dist[j] = dist[v] + g[v][j]; path[j] = v; } } } } int main(){ //读入数据 dijk(start); int shortest[maxn]; ofr(int i = 1; i <= n; i ++){ printf("%d\t", dist[i]); memset(shortest, 0, sizeof shortest); int k = 0; shortest[k] = i; while(path[shortest[k]] != 0){ k ++; shortest[k] = path[shortest[k-1]]; } k ++; shortest[k] = 0; for(int j = k; j > 0; j --){ printf("%d->", shortest[j]); } printf("%d\n", shortest[0]); } return 0; } SPFA #include<cstdio> #include<cstring> const int inf = ~0U>>1; const int maxn = 100;//点个数 struct node { int to, w; int next; }list[maxn]; int head[maxn]; int n; int dist[maxn]; int path[maxn]; int visit[maxn]; int q[maxn]; void spfa(int src){ for(int i = 0; i < n; i ++){ dist[i] = inf; path[i] = src; visit[i] = 0; } dist[src] = 0; path[src] = src; visit[src] = 1; int qs = 0, qe = 0; q[qe++] = src; while(qs <= qe){ int u = q[qs++]; visit[u] = 0; for(int i = head[u]; i != -1; i = list[i].next){ int v = list[i].to; if(dist[v] > dist[u] + list[i].w){ dist[v] = dist[u] + list[i].w; path[v] = u; if( !visit[v]){ q[qe++] = v; visit[v] = 1; } } } } } int index; void init(){ index = 0; memset(head, -1, sizeof head); } void add_edge(int u, int v, int w){ list[index].to = v; list[index].w = w; list[index].next = head[u]; head[u] = index ++; } int main(){ scanf("%d", &n); init(); while(true){ int u, v, w; scanf("%d%d%d", &u, &v, &w); if(u == -1 && v == -1 && w == -1) break; add_edge(u, v, w); } spfa(0); int shortest[maxn]; for(int i = 1; i < n; i ++){ printf("%d\t", dist[i]); memset(shortest, 0, sizeof shortest); int k = 0; shortest[k] = i; while(path[shortest[k]] != 0){ k ++; shortest[k] = path[shortest[k-1]]; } k ++; shortest[k] = 0; for(int j = k; j > 0; j --){ printf("%d->", shortest[j]); } printf("%d\n", shortest[0]); } return 0; } /* 1 6 2 5 3 5 4 -1 1 -2 4 1 2 -2 5 -1 6 3 6 3 -1 -1 -1 0->3->2->1 0->3->2 0->3 0->3->2->1->4 0->3->5 0->3->2->1->4->6 */ floyd const int inf = ~0U>>1; const int maxn = 100; int n; int g[maxn][maxn]; int path[maxn][maxn]; void floyd(){ for(int i = 0; i < n; i ++){ for(int j = 0; j < n; j ++){ if(i != j && g[i][j] < inf) path[i][j] = i; else path[i][j] = -1; } } for(int k = 0; k < n; k ++){ for(int i = 0; i < n; i ++){ for(int j = 0; j < n; j ++){ if(k == i || k == j) continue; if(g[i][k] + g[k][j] < g[i][j]){ g[i][j] = g[i][k] + g[k][j]; path[i][j] = path[k][j]; } } } } } int main(){ for(int i = 0; i < n; i ++){ for(int j = 0; j < n; j ++){ if(i == 0) g[i][j] = 0; else g[i][j] = inf; } } floyd(); int shortest[maxn]; for(int i = 0; i < n; i ++){ for(int j = 0; j < n; j ++){ if(i == j) continue; printf("%d=>%d\t%d\t", i, j, g[i][j]); memset(shortest, 0, sizeof shortest); int k = 0; shortest[k] = j; while(path[i][shortest[k]] != i){ k ++; shortest[k] = path[i][shortest[k-1]]; } k ++; shortest[k] = i; for(int t = k; t > 0; t --){ printf("%d->", shortest[t]); } printf("%d\n", shortest[0]); } } return 0; } 欧拉路径定理: ) 对于无向图,存在欧拉通路的充要条件:图连通,所有点奇度仅有两个或者0个,两个的是通路,0个的是回路 ) 对于有向图,存在欧拉通路的充要条件:图连通,出入度全相等;或者,出入为1的点为起点,出入为-1的点为终点,其它点出入度相等 欧拉路径:fleury算法//无向图!!! #include<cstdio> #include<cstring> int n,m; int e[100][100]; int top; int stack[100]; void dfs(int x){ top ++; stack[top] = x; for(int i = 1; i <= n; i ++){ if(e[x][i] > 0){ e[i][x] = e[x][i] = 0;//删除此边 dfs(i); break; } } } void fleury(int x){ top = 0; stack[top] = x; while(top >= 0){ int b = 0; for(int i = 1; i <= n; i ++){ if(e[stack[top]][i] > 0){ b=1; break; } } if(b == 0){//如果没有可以扩展就输出并出栈 printf("%d->",stack[top]); top--; } else{ top--; dfs(stack[top+1]); } } puts(""); } int main() { int degree, num, start;//顶点的度,奇度顶点个数,欧拉回路的起点 while(~scanf("%d%d", &n, &m)){ memset(e, 0, sizeof(0)); for(int i = 0; i < m; i ++){ int s, t; scanf("%d%d", &s, &t); e[s][t] = e[t][s] = 1; } num = 0, start = 1; //如果存在奇度顶点,则从奇度顶点出发,否则从顶点0出发 for(int i = 1; i <= n; i ++){ degree = 0; for(int j = 1; j <= n; j ++){ degree += e[i][j]; } if(degree%2) start = i, num++; } if(num == 0||num == 2) fleury(start); else puts("no"); } return 0; } /* 14 2 8 3 8 9 4 5 6 9 6 7 9 8 9 11 5 4 3 5 6 2 6 2 2 3 6 */ 网络流,SAP //http://poj.org/problem?id=1459 #include<cstdio> #include<cstring> using namespace std; const int inf = 100000000;//不要开太大 int n, np, nc, m; const int maxn = 105; int c[maxn][maxn];//残留网络 int s, t; int level[maxn], gap[maxn];//层次网络, 层结点数(用于间隙优化) int q[maxn], pre[maxn];//队列, 前驱 void init_sap(){ memset(level, 10, sizeof level); //for(int i = 0; i <= n ;i ++) level[i] = n + 1; memset(gap, 0, sizeof gap); int qs = 0, qe = 0; q[qe++] = t; level[t] = 0; gap[ level[t] ] ++; while(qs < qe){ int hd = q[qs++]; for(int i = 0; i < n; i ++){ if(level[i] > n && c[i][hd] > 0){ q[qe++] = i; level[i] = level[hd] + 1; gap[ level[i] ] ++; } } } } int find_path(int u){ for(int i = 0; i < n; i ++) if(c[u][i] > 0 && level[u] == level[i] + 1) return i; return -1; } int relabel(int u){ int tmp = inf; for(int i = 0; i < n; i ++) if(c[u][i] > 0 && tmp > level[i] + 1) tmp = level[i] + 1; if(tmp == inf) tmp = n; return tmp; } int sap(){ init_sap(); int flow = 0; int u = s; memset(pre, -1, sizeof pre); while(level[s] < n){ int v = find_path(u);//寻找允许弧 if(v >= 0){ pre[v] = u; u = v; if(u == t){//找到完整增广路 int min_flow = inf; for(int i = t; i != s; i = pre[i]) if(min_flow > c[ pre[i] ][i]) min_flow = c[ pre[i] ][i]; for(int i = t; i != s; i = pre[i]){ c[ pre[i] ][i] -= min_flow;//正向减 c[i][ pre[i] ] += min_flow; } flow += min_flow; u = s;//重新从源点找 } }else{//找不到弧 if( -- gap[ level[u] ] == 0) return flow;//更新断层 + 判断是否断层 v = relabel(u); gap[v] ++; level[u] = v;//重新标号 if(u != s) u = pre[u];//当前弧优化 } } return flow; } int main(){ while(~scanf("%d%d%d%d", &n, &np, &nc, &m)){ memset(c, 0, sizeof c); s = n, t = n + 1, n += 2; for(int i = 0; i < m; i ++){ int u, v, w; scanf(" (%d,%d)%d", &u, &v, &w); c[u][v] = w; } for(int i = 0; i < np; i ++){ int v, w; scanf(" (%d)%d", &v, &w); c[s][v] = w; } for(int i = 0; i < nc; i ++){ int u, w; scanf(" (%d)%d", &u, &w); c[u][t] = w; } int flow = sap(); printf("%d\n", flow); } return 0; } #include<cstdio> #include<cstring> using namespace std; const int inf = 100000000;//不要开太大 int n, np, nc, m; const int maxn = 105; int c[maxn][maxn];//残留网络 int s, t; int level[maxn], gap[maxn];//层次网络, 层结点数(用于间隙优化) int cur[maxn], pre[maxn]; int sap(){ memset(cur, 0, sizeof cur); memset(level, 0, sizeof level); memset(gap, 0, sizeof gap); int u = pre[s] = s, v; int flow = 0; int aug = inf; gap[s] = n;// gap[0] = n, gap[s] = t while(level[s] < n){ for(v = cur[u]; v < n; v ++){ if(c[u][v] > 0 && level[u] == level[v] + 1) break; } if(v < n){ pre[v] = u; if(aug > c[u][v]) aug = c[u][v]; u = cur[u] = v; if(u == t){ flow += aug; for(v = t; v != s; v = pre[v]){ c[ pre[v] ][v] -= aug; c[v][ pre[v] ] += aug; } aug = inf, u = s; } }else{ int min_label = n; for(v = 0; v < n; v ++){ if(c[u][v] > 0 && min_label > level[v]){ cur[u] = v; min_label = level[v]; } } if(--gap[level[u]] == 0) return flow; level[u] = min_label + 1; gap[ level[u] ] ++; u = pre[u]; } } return flow; } int main(){ while(~scanf("%d%d%d%d", &n, &np, &nc, &m)){ memset(c, 0, sizeof c); s = n, t = n + 1, n += 2; for(int i = 0; i < m; i ++){ int u, v, w; scanf(" (%d,%d)%d", &u, &v, &w); c[u][v] = w; } for(int i = 0; i < np; i ++){ int v, w; scanf(" (%d)%d", &v, &w); c[s][v] = w; } for(int i = 0; i < nc; i ++){ int u, w; scanf(" (%d)%d", &u, &w); c[u][t] = w; } int flow = sap(); printf("%d\n", flow); } return 0; } #include<cstdio> #include<cstring> struct Edge{ int to, next, w; }e[40000]; int head[300], index; int n, np, nc, m; int s, t; const int maxn = 110; int level[maxn], gap[maxn]; int cur[maxn], pre[maxn]; const int inf = 10000000; void add_edge(int u, int v, int w){ e[index].to = v; e[index].w = w; e[index].next = head[u]; head[u] = index ++; e[index].to = u; e[index].w = 0; e[index].next = head[v]; head[v] = index ++; } int sap(){ int u = pre[s] = s, v; int flow = 0; int aug = inf; memset(gap, 0, sizeof gap); memset(level, 0, sizeof level); for(int i = 0; i < n; i ++) cur[i] = head[i]; gap[s] = n; while(level[s] < n){ bool flag = false; for(int i = cur[u]; i != -1; i = e[i].next){ v = e[i].to; if(e[i].w > 0 && level[u] == level[v] + 1){ flag = true; if(e[i].w < aug) aug = e[i].w; pre[v] = u; u = v; if(u == t){ flow += aug; while(u != s){ u = pre[u]; e[cur[u]].w -= aug; e[cur[u]^1].w += aug; } aug = inf; } break; } cur[u] = e[i].next; } if(flag)continue; int min_label = n; for(int i = head[u]; i != -1; i = e[i].next){ v = e[i].to; if(e[i].w > 0 && min_label > level[v]){ min_label = level[v]; cur[u] = i; } } if(--gap[level[u]] == 0) return flow; level[u] = min_label + 1; gap[ level[u] ] ++; u = pre[u]; } return flow; } int main(){ while(~scanf("%d%d%d%d", &n, &np, &nc, &m)){ s = n, t = n + 1, n += 2; index = 0; memset(head, -1, sizeof head); for(int i = 0; i < m; i ++){ int u, v, w; scanf(" (%d,%d)%d", &u, &v, &w); add_edge(u, v, w); } for(int i = 0; i < np; i ++){ int v, w; scanf(" (%d)%d", &v, &w); add_edge(s, v, w); } for(int i = 0; i < nc; i ++){ int u, w; scanf(" (%d)%d", &u, &w); add_edge(u, t, w); } int flow = sap(); printf("%d\n", flow); } return 0; } http://poj.org/problem?id=2516 最小费用最大流—邻接表 #include<cstdio> #include<cstring> const int inf = 10000000; const int maxn = 110; struct Edge{ int u, v, w, c, next; }e[maxn * maxn * 4]; int head[maxn], index; void init_edge(){ memset(head, -1, sizeof head); index = 0; } void _add_edge(int u, int v, int w, int c){ e[index].u = u, e[index].v = v; e[index].w = w, e[index].c = c; e[index].next = head[u]; head[u] = index ++; } void add_edge(int u, int v, int w, int c){ _add_edge(u, v, w, c); _add_edge(v, u, -w, 0); } int q[1000000 + 10]; int visit[maxn]; int dist[maxn]; int pre[maxn]; int s, t, n; bool spfa(){ int qs = 0, qe = 0; memset(visit, 0, sizeof visit); memset(pre, -1, sizeof pre); for(int i = s; i <= t; i ++) dist[i] = inf; q[qe++] = s; visit[s] = 1; dist[s] = 0; while(qs < qe){ int now = q[qs++]; visit[now] = 0; for(int i = head[now]; i + 1; i = e[i].next){ int v = e[i].v; if(!e[i].c) continue; if(dist[v] == inf || dist[now] + e[i].w < dist[v]){ dist[v] = dist[now] + e[i].w; pre[v] = i; if(!visit[v]){ visit[v] = 1; q[qe++] = v; } } } } return dist[t] != inf; } int min_cost(){ int cost = 0; while(spfa()){ int flow = inf; for(int i = pre[t]; i != -1; i = pre[e[i].u]) if(flow > e[i].c) flow = e[i].c; for(int i = pre[t]; i != -1; i = pre[e[i].u]){ e[i].c -= flow; e[i^1].c += flow; } cost += flow * dist[t]; } return cost; } int N, M, K; int need[maxn][maxn]; int supply[maxn][maxn]; int m[maxn][maxn][maxn]; int main(){ while(scanf("%d%d%d", &N, &M, &K), N||M||K){ for(int i = 1; i <= N; i ++){ for(int j = 1; j <= K; j ++){ int a; scanf("%d", &a); need[i][j] = a; } } for(int i = 1; i <= M; i ++){ for(int j = 1; j <= K; j ++){ int a; scanf("%d", &a); supply[i][j] = a; } } for(int i = 1; i <= K; i ++){ for(int j = 1; j <= N; j ++){ for(int k = 1; k <= M; k ++){ int a; scanf("%d", &a); m[i][j][k] = a; } } } n = N + M; s = 0, t = n + 1; int ans = 0; for(int k = 1; k <= K; k ++){ init_edge(); for(int i = 1; i <= M; i ++){ add_edge(s, i, 0, supply[i][k]); } for(int i = 1; i <= M; i ++){ for(int j = 1; j <= N; j ++){ add_edge(i, j + M, m[k][j][i], inf); } } for(int i = 1; i <= N; i ++){ add_edge(i + M, t, 0, need[i][k]); } ans += min_cost(); bool flag = 0; for(int i = 1 + M; i <= N + M; i ++){ for(int j = head[i]; j + 1; j = e[j].next){ int v = e[j].v; if(v == t && e[j].c > 0){ flag = true; break; } } if(flag) break; } if(flag){ ans = -1; break; } } printf("%d\n", ans); } return 0; } 二分图最大匹配 #include<cstdio> #include<cstring> int k, m, n; bool g[510][510]; int visit[510], link[510]; bool dfs(int u){ for(int i = 1; i <= n; i ++){ if(g[u][i] && !visit[i]){ visit[i] = 1; if(link[i] == -1 || dfs(link[i])){ link[i] = u; return true; } } } return false; } int max_match(){ memset(link, -1, sizeof link); int ans = 0; for(int i = 1; i <= m; i ++){ memset(visit, 0, sizeof visit); if(dfs(i)) ans ++; } return ans; } int main(){ while(scanf("%d", &k), k){ scanf("%d%d", &m, &n); memset(g, 0, sizeof g); while(k --){ int u, v; scanf("%d%d", &u, &v); g[u][v] = true; } printf("%d\n", max_match()); } return 0; } http://acm.hdu.edu.cn/showproblem.php?pid=1269 强连通分量 #include<cstdio> #include<cstring> const int maxn = 10000 + 10; struct Edge{ int to, next; }e[maxn*10]; int head[maxn], index; int dfn[maxn], low[maxn]; int belong[maxn], vis[maxn]; int step, color;//时间戳,强连通分量个数 void add_edge(int u, int v){ e[index].to = v, e[index].next = head[u]; head[u] = index ++; } void init_edge(){ memset(head, -1, sizeof head); index= 0; } int n, m; int stack[maxn], top; void targan(int u){ dfn[u] = low[u] = ++step; stack[top++] = u; vis[u] = 1; for(int i = head[u]; i != -1; i = e[i].next){ int v = e[i].to; if(!dfn[v]){ targan(v); if(low[u] > low[v]) low[u] = low[v]; }else if(vis[v] && low[u] > dfn[v]) low[u] = dfn[v]; } if(dfn[u] == low[u]){ color ++; int s; do{ s = stack[--top]; vis[s] = 0; belong[s] = color; }while(s != u); } } void solve(){ memset(vis, 0, sizeof vis); memset(dfn, 0, sizeof dfn); memset(belong, -1, sizeof belong); step = color = top = 0; for(int i = 1; i <= n; i ++) if(!dfn[i]) targan(i); } int main(){ while(scanf("%d%d", &n, &m), n||m){ init_edge(); for(int i = 0; i < m; i ++){ int u, v; scanf("%d%d", &u, &v); add_edge(u, v); } solve(); if(color == 1) puts("Yes"); else puts("No"); } return 0; }