文件读写知识点:

写入文件: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;
}
}
05-08 15:34