ACM2作业
文件读写知识点:
写入文件:freopen("文件名", "r", stdin); 写出文件:freopen("文件名", "w", stdout);
不解释,上代码:
1、用Dijkstra算法求最短路径。
#include<iostream> #include<string> #include<cstring> using namespace std; //记录起点到每个顶点的最短路径的信息 struct Dis { string path; int value; bool visit; Dis() { visit = false; value = 0; path = ""; } }; class Graph_DG { private: int vexnum; //图的顶点个数 int edge; //图的边数 int **arc; //邻接矩阵 Dis * dis; //记录各个顶点最短路径的信息 public: //构造函数 Graph_DG(int vexnum, int edge); //析构函数 ~Graph_DG(); //顶点从1开始编号 bool check_edge_value(int start, int end, int weight); //创建图 void createGraph(); //求最短路径 void Dijkstra(int begin); //打印最短路径 void print_path(int); }; Graph_DG::Graph_DG(int vexnum, int edge) { //初始化顶点数和边数 this->vexnum = vexnum; this->edge = edge; //为邻接矩阵开辟空间和赋初值 arc = new int*[this->vexnum]; dis = new Dis[this->vexnum]; for (int i = 0; i < this->vexnum; i++) { arc[i] = new int[this->vexnum]; for (int k = 0; k < this->vexnum; k++) { //邻接矩阵初始化为无穷大 arc[i][k] = INT_MAX; } } } //析构函数 Graph_DG::~Graph_DG() { delete[] dis; for (int i = 0; i < this->vexnum; i++) { delete this->arc[i]; } delete arc; } //顶点从1开始编号 bool Graph_DG::check_edge_value(int start, int end, int weight) { if (start<2 || end<2 || start>vexnum || end>vexnum || weight < 0) { return false; } return true; } void Graph_DG::createGraph() { //cout << "请输入每条边的起点和终点(顶点编号从s开始)以及其权重" << endl; int start,end,weight,count=0; while (count != this->edge) { cin >> start >> end >> weight; //对邻接矩阵对应上的点赋值 arc[start - 1][end - 1] = weight; ++count; } } void Graph_DG::Dijkstra(int begin) { //首先初始化我们的dis数组 int i; for (i = 0; i < this->vexnum; i++) { //设置当前的路径 //dis[i].path = "v" + to_string(begin) + "-->v" + to_string(i + 1); dis[i].path = to_string(begin) + " " + to_string(i + 1); dis[i].value = arc[begin - 1][i]; } //设置起点的到起点的路径为0 dis[begin - 1].value = 0; dis[begin - 1].visit = true; int count = 1; //计算剩余的顶点的最短路径(剩余this->vexnum-1个顶点) while (count != this->vexnum) { //temp用于保存当前dis数组中最小的那个下标 //min记录的当前的最小值 int temp = 0; int min = INT_MAX; for (i = 0; i < this->vexnum; i++) { if (!dis[i].visit && dis[i].value<min) { min = dis[i].value; temp = i; } } //cout << temp + 1 << " "<<min << endl; //把temp对应的顶点加入到已经找到的最短路径的集合中 dis[temp].visit = true; ++count; for (i = 0; i < this->vexnum; i++) { //注意这里的条件arc[temp][i]!=INT_MAX必须加,不然会出现溢出,从而造成程序异常 if (!dis[i].visit && arc[temp][i] != INT_MAX && (dis[temp].value + arc[temp][i]) < dis[i].value) { //如果新得到的边可以影响其他为访问的顶点,那就就更新它的最短路径和长度 dis[i].value = dis[temp].value + arc[temp][i]; dis[i].path = dis[temp].path + " " + to_string(i + 1); } } } } void Graph_DG::print_path(int begin) { for (int i = 0; i != this->vexnum; i++) { if (dis[i].value != INT_MAX) { cout<< dis[i].value << endl; } else { cout << "Infinite" << endl; } cout << dis[i].path << endl; } } bool check(int Vexnum, int edge) { if (Vexnum <= 0 || edge <= 0 || ((Vexnum*(Vexnum - 1)) / 2) < edge) return false; return true; } int main() { //freopen("Dijkstra_in.txt", "r", stdin); //freopen("Dijkstra_out.txt", "w", stdout); int t; cin >> t; while (t--) { int vexnum,edge,s; cin >> vexnum >> edge >> s; Graph_DG graph(vexnum, edge); graph.createGraph(); graph.Dijkstra(s); graph.print_path(s); system("pause"); } return 0; }
2、用Prim算法求最小生成树。
#include <stdio.h> #include <string.h> #include <iostream> #define maxn 100 #define inf 0x3f3f3f3f using namespace std; int i,j,G[maxn+1][maxn+1];//构建的图,必须是一个无向连通赋权图,G[i][j]存取权值*/ int intree[maxn];//结点i在最小生成树中*/ int minw[maxn];//到i点的最小权重*/ int sumw; void init() { memset(intree,0,sizeof(intree)); memset(minw,0,sizeof(minw)); for(i = 0 ; i <= maxn ; i++) for(j = 0 ; j <= maxn ; j++) G[i][j] = inf; sumw = 0; } void prime(int n) { int node,Minw; for(i = 1 ; i <= n ; i++) minw[i] = G[1][i]; //先把1结点放进最小生成树,那么要知道1到其余结点的最小权重 intree[1] = 1;//1点进入集合A,最小生成树集 for(i = 2 ; i <= n ; i++) //一共n个点,已经把1加入最小生成树,那么还剩下n-1个点 { Minw = inf; for(j = 1 ; j <= n ; j++) { if(minw[j] < Minw && !intree[j]) { Minw=minw[j]; node=j; } } printf("选择的结点标号为:%d\n",node); intree[node]=1; sumw+=Minw; //每次在A中加入新的点,更新顶结点到各节点的权重 for(j=1;j<=n;j++) if(!intree[j]&&minw[j]>G[node][j]) //更新B集合 minw[j]=G[node][j]; } } int main() { //freopen("Prim_in.txt", "r", stdin); //freopen("Prim_out.txt", "w", stdout); int N,M,a,b,w; while(cin>>N>>M,N,M) { init(); for(i=1;i<=M;i++) { cin>>a>>b>>w; G[a][b]=w; G[b][a]=w; } prime(N); cout<<sumw<<endl; } return 0; } /*测试数据 4 5 1 4 1 1 2 6 2 3 3 2 4 4 3 4 2 6 9 1 2 6 1 3 1 1 4 5 2 3 5 2 5 3 3 4 5 3 6 4 4 6 2 5 6 6 0 0 */
3、数字三角形,题意随便模拟一下就好,既可以用暴力解决也可以用动态规划解决。
#include <iostream> #include <algorithm> #include <cstring> #define maxn 10000+5 using namespace std; int D[maxn][maxn]; int memon[maxn][maxn]; int num; //menon数组记忆每一次计算后的值,避免重复计算,O(n^2) int MinSum(int i, int j) { if(memon[i][j] != -1) return memon[i][j]; if(i == num) memon[i][j] = D[i][j]; else{ int x = MinSum(i + 1, j); int y = MinSum(i + 1, j + 1); memon[i][j] = min(x,y) + D[i][j]; } return memon[i][j]; } int main() { int i, j; while(cin >> num,num) { memset(memon,-1,sizeof(memon)); for(i = 1; i <= num; i ++) for(j = 1; j <= i; j ++) cin >> D[i][j]; cout << MinSum(1,1) << endl; } return 0; }
4、求两个子序列的最长公共子序列的长度并且输出最长公共子序列。
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; const int maxn = 1000 + 5; int n, m; long long a[maxn], b[maxn]; int f[maxn][maxn]; int pre[maxn][maxn]; int main() { freopen("LCS_in.txt", "r", stdin); freopen("LCS_out.txt", "w", stdout); int t,i,j; cin>>t; while(t--) { cin>>n; for(i=1;i<=n;i++) scanf("%lld",a+i); cin>>m; for(i=1;i<=m;i++) scanf("%lld",b+i); memset(pre, -1, sizeof(pre)); memset(f, 0, sizeof(f)); for(i=1;i<=n;i++) { int v=0,k=0; for(j=1;j<=m;j++) { f[i][j]=f[i-1][j]; if(a[i]>b[j]&&v<f[i-1][j]) v=f[i-1][j],k=j; if(a[i]==b[j]&&v+1>f[i][j]) f[i][j]=v+1,pre[i][j]=k; } } int k=1; for(i=1;i<=m;i++) if(f[n][i]>f[n][k]) k=i; cout<<f[n][k]<<endl; if(f[n][k]==0) continue; vector<int> ans; for(i=n;i>=1;i--) if(pre[i][k]!=-1) ans.push_back(a[i]),k=pre[i][k]; cout<<ans.back(); for(i=ans.size()-2;i>=0;i--) cout<<" "<<ans[i]; cout<<endl<<endl; } }
5、两条线段是否相交。
#include <iostream> #include <cstdio> using namespace std; int main() { freopen("line_in.txt", "r", stdin); freopen("ine_out.txt", "w", stdout); double x1,x2,x3,x4,y1,y2,y3,y4,k1,k2; double w1,w2,w3,w4; while(cin>>x1>>y1>>x2>>y2>>x3>>y3>>x4>>y4) { int flag=0; if((x2-x1)==0) //如果斜率不存在 { if((x3>=x2&&x4<=x2)||(x4>=x2&&x3<=x2)) flag+=1; } else //如果存在 { k1=(y2-y1)/(x2-x1); w3=k1*(x3-x2)+y2; w4=k1*(x4-x2)+y2; if((y3>=w3&&y4<=w4)||(y3<=w3&&y4>=w4)) //看图模拟一遍 flag+=1; } if((x4-x3)==0) //继续判断斜率是否存在 { if((x2>=x3&&x1<=x3)||(x1>=x3&&x2<=x3)) flag+=1; } else { k2=(y4-y3)/(x4-x3); w1=k2*(x1-x3)+y3; w2=k2*(x2-x3)+y3; if((y2>=w2&&y1<=w1)||(y2<=w2&&y1>=w1)) flag+=1; } if(flag==2) cout<<"yes"<<endl; else cout<<"no"<<endl; } return 0; }
6、计算凸多边形面积。
#include<iostream> #include<cmath> #include<cstdio> #include<iomanip> using namespace std; struct point { double x; double y; }; point a[100]; double area(point m,point n) { return (m.x*n.y - m.y*n.x)/2; } int main() { freopen("polygon_in.txt", "r", stdin); freopen("polygon_out.txt", "w", stdout); int n; while(cin>>n,n) { for(int i = 0;i<n;i++) cin>>a[i].x>>a[i].y; double sum = area(a[n-1],a[0]); for(int i = 1;i<n;i++) { sum+=area(a[i-1],a[i]); } cout<<fixed<<setprecision(2)<<sum<<endl; } }