2014年9月6日,图的方面,我不太懂。就慢慢学吧
/* warshall-floyd d[i][j]?????i->j??????? */ #include<iostream> using namespace std; int V; const int MAXN=1<<10; int d[MAXN][MAXN]; void warshall_floyd(){ for(int k=0;k<V;k++) for(int i=0;i<V;i++) for(int j=0;j<V;j++){ d[i][j]=min(d[i][j],d[i][k]+d[k][j]); } } int main(){ warshall_floyd(); return 0; }
/* dijkstra算法,选最小点d更新边,即加边操作 适用于无负权的图问题 */ #include<iostream> #include<vector> #include<queue> using namespace std; const int MAXN=1<<10; int cost[MAXN][MAXN];//从u->v的权值 int V,d[MAXN],INF=(1<<31)-1; bool used[MAXN]; /* d[v],cost[u][v]来存储 */ void dijkstra1(int s){ fill(d,d+V,INF); fill(used,used+V,false); d[0]=0; while(true){ int v=-1; //选择一个没有使用的最小值的点 for(int u=0;u<V;u++){ if(!used[u] &&(v==-1 || d[u] <d[v])) v=u; } if(v==-1) break; //未选择出来 used[v]=true; //更新所有的点的最小距离 更新操作太多,浪费时间 for(int u=0;u<V;u++) d[u]=min(d[u],d[v]+cost[v][u]); } } /* 采用邻接表+堆[查找最小值],复杂度ElogV */ struct edge{ int to,cost; }; vector<edge> G[MAXN]; typedef pair<int ,int> P; // first 代表最短距离,second代表顶点编号 void dijkstra2(int s){ priority_queue<P, vector<P>, greater<P> > que; fill(d,d+V,INF); que.push(P(0,s)); //初始化 while(!que.empty()){ P p= que.top(); que.pop(); int v=p.second; //取出编号 if(d[v]<p.first) continue; //检查与d是否是最小的,确定是否更新d for(int i=0;i<G[v].size();i++){ //更新v的连接边 edge e=G[v][i]; if(d[e.to]<d[v]+e.cost){ d[e.to]=d[v]+e.cost; que.push(P(d[e.to],e.to)); //将更新后的最小边加入que } } } } int main(){ dijkstra1(0); dijkstra2(0); return 0; }
/* 总结的都在下面了 */ #include<iostream> using namespace std; const int MAXN=1<<10; struct edge{ int from,to,cost; }; edge es[MAXN]; int V,E,d[MAXN],INF=(1<<31)-1; void input(){ } /* bellman-ford算法,适用于负边的情况 选边更新点d,即加点操作 最终d[V]数组代表起点s到每个点i最短路的值 */ void shortest_path(int s){ for(int i=0;i<V;i++) d[i]=INF; d[0]=0; bool update; while(1){ update=false; for(int i=0;i<E;i++){ edge e=es[i];//选边 //满足加点,A->B。A已访问,并A->B产生最小值d,需要更新d if(d[e.from]!=INF&& d[e.to]>d[e.from]+e.cost){ d[e.to]=d[e.from]+e.cost; update=true; } } if(!update) break; } } /* v-1次循环最多,如果v-1次继续更新,可以判定为存在负圈 */ bool find_negative_loop(){ memset(d,0x00,sizeof(d)); for(int i=0;i<V;i++){ for(int j=0;j<E;j++){ edge e=es[j]; if(e.to>e.from+e.cost){ d[e.to]=d[e.from]+e.cost; if(i==V-1) return true; } } } return false; } int main(){ input(); shortest_path(0); find_negative_loop(); return 0; }
/* dfs染色 ,没有图数据,随便找找吧 3 No 4 Yes */ #include<iostream> #include <vector> using namespace std; const int MAXN=1<<10; vector<int> G[MAXN]; int V,color[MAXN]; void input(){ scanf("%d",&V); } bool dfs(int v,int c){ color[v]=c; //染色改点 for(int i=0;i<G[v].size();i++){//染色其他点 //相邻两个相同返回flase if(color[G[v][i]]==c) return false; //相邻没有染色,继续染色 if(color[G[v][i]]== 0 && !dfs(G[v][i],-c)) return false; } return true; } void sovle(){ for(int i=0;i<V;i++){ if(color[i]==0 && !dfs(i,1)){ printf("No\n"); return; } } printf("Yes\n"); } int main(){ input(); sovle(); return 0; }
/* 话说并查集的问题真的很多,这题的代码,以后就盲打吧。以后用的找、比如说dijikstra算法等,都会使用并查集来判断是不是同在一个连通分量里面 100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5 3 */ #include<iostream> using namespace std; const int MAXN=1<<10; int par[MAXN],rank[MAXN]; const int MAXK=1<<15; int N,K; int T[MAXK],X[MAXK],Y[MAXK]; void init(int n){ for(int i=0;i<n;i++){ par[i]=i; rank[i]=0; } } int find(int x){ if(par[x]==x) //根部 return x; else return par[x]=find(par[x]); //路径压缩 :x的父亲节点连接根部 } void unite(int x,int y){ x=find(x); y=find(y); if(x==y) return; //属于同一个集合 if(rank[x]<rank[y]) par[x]=y; else{ par[y]=x; if(rank[x]==rank[y]) rank[x]++; } } bool same(int x,int y){ return find(x)==find(y); } void input(){ scanf("%d%d",&N,&K); int i=0; while(i<K) scanf("%d %d %d",&T[i],&X[i],&Y[i++]); } void sovle(){ init(N*3); int ans=0; for(int i=0;i<K;i++){ int t=T[i]; int x=X[i]-1,y=Y[i]-1; //0~N-1 if(x<0 || x>=N || y<0 || y>=N){ //非法数据 ans++; printf("K=%d\n",(i+1)); continue; } if(t==1){ //x,y属于同一类 if(same(x,y+N)|| same(x,y+2*N)) { //矛盾,与B,C同一集合 ans++; printf("K=%d\n",(i+1)); }else{ //合并集合 unite(x,y); unite(x+N,y+N); unite(x+2*N,y+2*N); } }else { //x吃y A,B,C分别不同类 if(same(x,y)||same(x,y+2*N))//X-A,Y-A不同类,X-A,Y-B也不同类 { ans++; printf("K=%d\n",(i+1)); }else{ unite(x,y+N); unite(x+N,y+2*N); unite(x+2*N,y); } } } printf("%d\n",ans); } int main(){ input(); sovle(); return 0; }
/* STL:set采用二叉搜索树来维护集合的,map是维护键值对的容器 能存储重复值的容器multiset,multimap */ #include <cstdio> #include<set> #include<map> #include<string> using namespace std; void test_set(){ set<int > s; s.insert(1); s.insert(3); s.insert(5); set<int >::iterator ite; ite=s.find(1); //查找 if(ite==s.end()) puts("No"); else puts("Yes"); if(s.count(3)!=0)puts("Yes"); //统计 else puts("No"); s.erase(1); //删除 for(ite=s.begin();ite!=s.end();ite++) //遍历 printf("%d ",*ite); } void test_map(){ printf("\n--map--\n"); map<int,const char* > m; m.insert(make_pair(0,"ONE")); //插入 m.insert(make_pair(10,"TEN")); m[100]="HUNDRED"; //插入 map<int,const char* >::iterator ite; ite=m.find(1); //查找 if(ite==m.end())puts("No"); else puts(ite->second); puts(m[100]); m.erase(10); //删除 for(ite=m.begin();ite!=m.end();ite++)//遍历 printf("%d %s \n",ite->first,ite->second); } int main(){ test_set(); test_map(); return 0; }
/* 3 8 5 8 34 */ #include<cstdio> #include<queue> using namespace std; const int MAXN=1<<10; int n,L[MAXN]; void input(){ scanf("%d",&n); int i=0; while(i<n) scanf("%d",&L[i++]); } void sovle(){ priority_queue<int ,vector<int>,greater<int> > que; //优先队列从小取值 for(int i=0;i<n;i++) que.push(L[i]); int ans=0; while(que.size()>1){ int min1=que.top(); que.pop(); int min2=que.top(); que.pop(); que.push(min1+min2); ans+=min1+min2; } printf("%d\n",ans); } int main(){ input(); sovle(); return 0; }
/* 4 25 10 10 14 20 21 10 5 2 4 2 */ #include<cstdio> #include<queue> using namespace std; const int MAXN=1<<7; int N,L,P,A[MAXN],B[MAXN]; void input(){ scanf("%d%d%d",&N,&L,&P); int i=0; while(i<N)scanf("%d",&A[i++]); i=0; while(i<N)scanf("%d",&B[i++]); } void sovle(){ A[N]=L; B[N]=0; N++; int ans=0,pos=0,tank=P; //pos位置,tank车上的油量剩余量 priority_queue<int> pqu; for(int i=0;i<N;i++){ //加油站个数 int d=A[i]-pos; //前进距离 while(tank-d<0){ //加油至下一个加油站 if(pqu.empty()){ printf("-1"); return; } tank+=pqu.top(); pqu.pop(); ans++; } //更新车子参数 tank-=d; pos=A[i]; //加入下一个加油量 pqu.push(B[i]); //加入油站 } printf("%d\n",ans); } int main(){ input(); sovle(); return 0; }
/* priority_queue pop出最大值,用最大堆来维护存储 */ #include<queue> #include<cstdio> using namespace std; int main(){ priority_queue <int > pqu; pqu.push(1); pqu.push(20); pqu.push(3); while(!pqu.empty()){ printf("%d\n",pqu.top()); pqu.pop(); } return 0; }
/* dp求解组合:从不同数量的n种物品选择m个的组合总数 3 3 1 2 3 10000 6 */ #include<iostream> using namespace std; const int MAXN=1<<10; int n,m,a[MAXN],M,dp[MAXN][MAXN]; void input(){ scanf("%d%d",&n,&m); int i=0; while(i<n)scanf("%d",&a[i++]); scanf("%d",&M); } /* dp[i+1][j],从前i中取j个的组合数 dp[i+1][j]=dp[i+1][j-1]+dp[i][j]-dp[i][j-1-a[i]] */ void sovle(){ //前i个取0个的组合数只有1种 for(int i=0;i<n;i++) dp[i][0]=1; for(int i=0;i<n;i++) for(int j=0;j<=m;j++) if(j-1-a[i]>=0) dp[i+1][j]=(dp[i+1][j-1]+dp[i][j]-dp[i][j-1-a[i]]+M)%M; else dp[i+1][j]=dp[i+1][j-1]+dp[i][j]; printf("%d\n",dp[n][m]); } int main(){ input(); sovle(); return 0; }