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;
    }
}
posted @ 2017-11-15 12:26  codeg  阅读(862)  评论(0编辑  收藏  举报