版权声明:欢迎评论交流,转载请注明原作者。 https://blog.csdn.net/m0_37809890/article/details/83140781
截图打卡
总结
- map的operator[]操作会在目标元素不存在时新建一个元素,无副作用的检验元素是否存在应该使用map.count()
- 跳过了本章指针建树与手动内存池的部分,以后再学。
- 多组数据题,完全可以while(init()),init包括了初始化与读入工作。
- list.insert(iter,val),在iter左边插入,不改变iter,返回被插入位置的迭代器。
- 拓扑排序:dfs,访问完一个节点之后把它加在拓扑序的首部,这个方法也能用来判环。
- 网格与点转化,带离散化的情况,参考第18题
- 第20题,刘老师有更快的方法,日后回来看。
- 要学会合理建图(废话)
题目
- uva210 模拟
大模拟题,读清题意,想好数据结构,单元测试 - uva514 栈原理
用类似于双指针的操作。 - uva442 表达式解析
表达式解析的常规套路:想好栈中元素,想好元素初值,画自动机int ans = 0; int sl = 0, sr = 0; stack<pair<int,int>> st; for(auto c:expr) { if(isalpha(c)) { if(sl==0) { sl = lef[c], sr = rig[c]; } else { ans += sl * lef[c] * rig[c]; sr = rig[c]; } } else if(c=='(') { st.emplace(sl,sr); sl = 0, sr = 0; } else if(c==')') { int xl = st.top().first, xr = st.top().second; st.pop(); ans += xl*max(xr,sl)*sr; if(xl) sl=xl; if(sr==0) sr=xr; } //printf("sl=%d sr=%d stack=%d\n",sl,sr,st.size() ); }
- uva11988 链表
熟悉std::list的操作 - uva12657
双向链表,很好的一道题,以后可以再写一遍。
加标记,提前保存,函数扩展。/* LittleFall : Hello! */ #include <bits/stdc++.h> using namespace std; using ll = long long; inline int read(); const int M = 500016, MOD = 1000000007; int pre[M], nxt[M]; inline void link(int x, int y) { nxt[x]=y; pre[y]=x; } int main(void) { int n,m,kase=0; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;++i) { pre[i] = i-1; nxt[i] = i+1; } nxt[0] = 1, pre[n+1] = n; int inv = 0; while(m--) { int op = read(); if(op==4) { inv^=1; continue; } int x = read(), y = read(); int lx = pre[x], ly = pre[y], rx = nxt[x], ry = nxt[y]; if(op<3 && inv) op = 3 - op; if(op==1 && nxt[x]!=y) { link(lx,rx); link(ly,x); link(x,y); } if(op==2 && pre[x]!=y) { link(lx,rx); link(y,x); link(x,ry); } if(op==3) { if(x==pre[y]) { link(lx,y); link(y,x); link(x,ry); } else if(y==pre[x]) { link(ly,x); link(x,y); link(y,rx); } else { link(lx,y); link(ly,x); link(y,rx); link(x,ry); } } } int cnt = 1; ll ans = 0; for(int i=nxt[0];i!=n+1;i=nxt[i]) { //printf("%d\n",i ); if(cnt^inv) ans += i; cnt^=1; } printf("Case %d: %lld\n",++kase,ans ); } return 0; }
- uva 679
算结论题 - uva 122
输入处理 - uva 548 由中序和后序建树,经典题
int n, nxt = 0; //新插位置 int in_order[M], post_order[M], anti_in[M]; //中序,后序 int ans = 0, miamount = INT_MAX, mival = INT_MAX; struct Node { int val; int amount; vector<int> son; }node[M]; int solve(int in_lef, int post_lef, int length) //中序左边界,后序左边界,长度 { int n_id = nxt++; //节点存储编号 node[n_id].val = post_order[post_lef+length-1]; //根节点的值 int in_rt = anti_in[node[n_id].val]; //获得根节点在中序中的下标 int lef_len = in_rt - in_lef, rig_len = length - 1 - lef_len; //左右子树的节点数 if(lef_len) node[n_id].son.push_back(solve(in_lef, post_lef, lef_len)); if(rig_len) node[n_id].son.push_back(solve(in_rt+1, post_lef+lef_len, rig_len)); return n_id; } void dfs(int now, int lst) //当前节点,之前路径上的权值和 { node[now].amount = node[now].val + lst; if(node[now].son.empty() && (node[now].amount<miamount || (node[now].amount == miamount && node[now].val<mival))) { ans = now; miamount = node[now].amount; mival = node[now].val; } for(auto nxt:node[now].son) dfs(nxt, node[now].amount); } inline bool init() //初始化与读入,失败返回0 { nxt = n = 0; ans = 0; miamount = mival = INT_MAX; memset(node,0,sizeof(node)); string tmp; stringstream sin; getline(cin,tmp); if(tmp=="") return 0; sin = stringstream(tmp); while(sin >> in_order[n+1]) ++n; getline(cin,tmp); sin = stringstream(tmp); for(int i=1;i<=n;++i) sin >> post_order[i]; return n; } int main(void) { #ifdef _LITTLEFALL_ freopen("in.txt","r",stdin); #endif while(init()) { for(int i=1;i<=n;++i) anti_in[in_order[i]] = i; solve(1,1,n); dfs(0,0); printf("%d\n",node[ans].val ); } return 0; }
- Uva 839 经典结构,输入,递归,传递引用,返回
- uva 699 递归
- uva 297 四分树
年轻的时候做过这道题,没做出来。
把四分树表示的图像画出来就好了。 - uva572 dfs求连通块
- uva1103 代码结构要明确,dfs函数写一个就行。
/* LittleFall : Hello! */ #include <bits/stdc++.h> using namespace std; using ll = long long; inline int read(); const int M = 256, MOD = 1000000007; const int go[4][2] = {{0,1},{0,-1},{-1,0},{1,0}}; const char ch[7] = {'W','A','K','J','S','D'}; int mp[M][M],tag[M][M],n,m; int ans[M*M]; char out[M*M]; //把相邻的颜色为co的都打上st的标记 void dfs(int i,int j,int co,int st) { tag[i][j] = st; for(int k=0;k<4;++k) { int ni = i+go[k][0], nj = j+go[k][1]; if(ni>=0 && ni<=n+1 && nj>=0 && nj<=m+1 && mp[ni][nj]==co && tag[ni][nj]==0) dfs(ni,nj,co,st); } return; } /*Process Function*/ int init() { scanf("%d%d",&n,&m); if(n==0) return 0; m<<=2; memset(mp,0,sizeof(mp)); memset(tag,0,sizeof(tag)); memset(ans,0,sizeof(ans)); memset(out,0,sizeof(out)); char tmp[64]; for(int i=1;i<=n;++i) { scanf("%s",tmp+1); for(int j=1;tmp[j];++j) { int num = isalpha(tmp[j])?tmp[j]-'a'+10:tmp[j]-'0'; for(int k=0;k<4;++k) mp[i][(j-1)*4+1+k] = (num>>(3-k))&1; } } return 1; } int main(void) { int kase = 0; while(init()) { int bls=0; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { if(mp[i][j]==1 && tag[i][j]==0) dfs(i,j,1,++bls); } dfs(0,0,0,-1); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(mp[i][j]==1) { for(int k=0;k<4;++k) { int ni=i+go[k][0],nj=j+go[k][1]; if(mp[ni][nj]==0 && tag[ni][nj]==0) { ++ans[tag[i][j]]; dfs(ni,nj,0,tag[i][j]); } } } for(int i=1;i<=bls;++i) out[i]=ch[ans[i]]; sort(out+1,out+bls+1); printf("Case %d: %s\n",++kase,out+1 ); } return 0; }
- uva816 带方向的迷宫
认清问题实质,然后bfs - uva10305 拓扑排序
dfs,把新访问完的放在最前面 - uva10129 欧拉路
- 无向图,欧拉圈:没有奇度数点。
- 无向图,欧拉路:没有奇度数点或只有两个
- 有向图,欧拉圈:所有节点入度=出度
- 有向图,欧拉路:满足上述条件,或者有一节点入度=出度+1且有一节点出度=入度+1,其它节点全部入度=出度。
- 图必须连通(有向图为底图连通)
- uva10562 递归
注意字符集不一定是小写字母,isprint()判断可打印字符(包括空白字符),isgraph()不包括空白字符 - UVA - 12171 Sculpture 离散化,网格与点的转化
- uva1572 建图,判环
以字母+符号为点,正方形看成边,建立一个有向图。注意每条边的起点不变,终点变成它的共轭。当且仅当图中有环时输出yes。set<int> edg[M]; int vis[M]; //0未访问,1正在访问,2访问结束 bool dfs(int u) { vis[u] = 1; for(auto v:edg[u]) { if(vis[v]==1) return false; else if(vis[v]==0) if(!dfs(v)) return false; } vis[u] = 2; return true; } bool noloop() { for(int i=0;i<52;++i) if( !vis[i] && !dfs(i) ) return false; return true; } int init() { for(int i=0;i<M;++i) edg[i].clear(); memset(vis,0,sizeof(vis)); int n; if(scanf("%d",&n)==-1) return 0; char tmp[10]; for(int i=0;i<n;++i) { scanf("%s",tmp); for(int id1=0;id1<4;++id1) { for(int id2=id1+1;id2<4;++id2) if(tmp[id1*2]!='0' && tmp[id2*2]!='0') { int u = (tmp[id1*2]-'A')*2 + (tmp[id1*2+1]=='+'); int v = (tmp[id2*2]-'A')*2 + (tmp[id2*2+1]=='+'); edg[u].insert(v^1), edg[v].insert(u^1); } } } return n; } int main(void) { #ifdef _LITTLEFALL_ freopen("in.txt","r",stdin); #endif while(init()) { printf("%s\n",noloop()?"bounded":"unbounded" ); } return 0; }
- uva1599 bfs
给一无向图,每条边都有一个权值。求起点到终点的一条路径,要求经过的边数最小,且边权序列的字典序最小。
反向bfs一遍,然后从起点开始逐距离把所有边权最小的点的记录下来,每次仅从边权最小的点向后转移。注意有自环或重边,所以需要对记录去重,否则记录数量会变成指数。int n,m; struct Node{ int fst; int dis; //距终点的距离 }nod[N]; struct Edge{ int pnt,nxt,pri; }edg[M]; int ect; void addEdge(int u,int v,int p) { edg[++ect].pnt = v; edg[ect].pri = p; edg[ect].nxt = nod[u].fst; nod[u].fst = ect; } set<int> per[N]; //距离终点i的可选择序列 int init() { if(scanf("%d%d",&n,&m)==-1) return 0; memset(nod,-1,sizeof(nod)); memset(edg,0,sizeof(edg)); for(int i=0;i<N;++i) per[i].clear(); ect = 0; while(m--) { int a=read(),b=read(),c=read(); addEdge(a,b,c); addEdge(b,a,c); } return 1; } void bfs(int st) { queue<int> q; nod[st].dis = 0; q.push(st); while(!q.empty()) { int u = q.front(); q.pop(); for(int vd=nod[u].fst; ~vd; vd=edg[vd].nxt) { int v = edg[vd].pnt; if(nod[v].dis == -1) { nod[v].dis = nod[u].dis+1; q.push(v); } } } } int main(void) { #ifdef _LITTLEFALL_ freopen("in.txt","r",stdin); #endif while(init()) { bfs(n); int tot = nod[1].dis; printf("%d\n",tot ); per[tot].insert(1); for(int dis = tot; dis; --dis) { int ans = MOD; for(auto u:per[dis]) for(int vd=nod[u].fst; ~vd; vd=edg[vd].nxt) if(nod[ edg[vd].pnt ].dis == dis-1) ans = min(ans, edg[vd].pri); for(auto u:per[dis]) for(int vd=nod[u].fst; ~vd; vd=edg[vd].nxt) { int v = edg[vd].pnt; if(nod[v].dis == dis-1 && edg[vd].pri==ans) per[dis-1].insert(v); } printf("%d%c",ans,dis==1?'\n':' ' ); } } return 0; }
- uva506 大模拟 题目没给数据范围,应该在10000左右.
- uva11853 简单计算几何,dfs
正方形内有n个圆形障碍物,问能否从左边界走到右边界,如果可以,求最北边的进入点和离去点。
把每个障碍物视作一个点,如果两个圆相交,那么它们有边相连。当且仅当与上边界相交的圆连通的圆与下边界相交时,无法走通。能走通时,最北边的进入点就是与上边界连通的圆与左边界的最南方交点,离去点同理。int n, ect; struct Node{ int fst; //graph int x,y,r; //circle int vis; //dfs }nod[M]; struct Edge{ int nxt,pnt; }edg[M]; inline void addEdge(int a, int b) { edg[++ect].pnt = b; edg[ect].nxt = nod[a].fst; nod[a].fst = ect; } int fail = 0; double lin = 1000, lout = 1000; void dfs(int u) { nod[u].vis = 1; for(int vd=nod[u].fst; vd; vd=edg[vd].nxt) { int v = edg[vd].pnt; if(!nod[v].vis) dfs(v); } int r = nod[u].r, x = nod[u].x, y = nod[u].y; if(y-r<=0) fail = 1; if(x-r<=0) lin = min(lin,y-sqrt(r*r-x*x)); if(x+r>=1000) lout = min(lout,y-sqrt(r*r-(1000-x)*(1000-x))); } int init() { //init n = ect = fail = 0; lin = lout = 1000.0; memset(nod,0,sizeof(nod)); memset(edg,0,sizeof(edg)); //read if(scanf("%d",&n)==-1) return 0; for(int i=1;i<=n;++i) { nod[i].x = read(); nod[i].y = read(); nod[i].r = read(); } //build for(int i=1;i<=n;++i) { int ax = nod[i].x, ay = nod[i].y, ar=nod[i].r; for(int j=i+1;j<=n;++j) { int bx = nod[j].x, by = nod[j].y, br=nod[j].r; if((ax-bx)*(ax-bx)+(ay-by)*(ay-by)<=(ar+br)*(ar+br)) //不相离 addEdge(i,j), addEdge(j,i); } } return 1; } int main(void) { #ifdef _LITTLEFALL_ freopen("in.txt","r",stdin); #endif while(init()) { for(int i=1;i<=n;++i) if(!nod[i].vis && nod[i].y+nod[i].r>=1000) dfs(i); if(fail) printf("IMPOSSIBLE\n"); else printf("0.00 %.2f 1000.00 %.2f\n",lin,lout ); } return 0; }