【矿大】中国矿业大学 CUMT 信息安全管理与工程2024春季学期 OpenJudge OJ 问题 D: 层次分析法(AHP)

题目

样例输入

3
1 1/3 1/3
3 1 1
3 1 1
2
1 1/4
4 1
1 1/3
3 1
1 7
1/7 1

样例输出

0.5107 0.4893

题解

这题目,看到就觉得亲切,这不是上一篇文章里提到的模糊层次分析法中的一步吗,而且还不需要一致性检验,真是太简单了,一开始是这样想的于是写了两个函数

//计算特征向量
vector<double> ComputeCharacteristicVector(vector<vector<double>> m)
{
	//列向量归一化
	//建立临时阵,使其大小等于传入阵
	vector<vector<double>> mtem = m;
	for (int i = 0; i < m.at(0).size(); i++)
	{
		double sum = 0;
		for (int j = 0; j < m.size(); j++)
		{
			sum += m.at(j).at(i);
		}
		for (int j = 0; j < m.size(); j++)
		{
			mtem[j][i] = m.at(j).at(i) / sum;
		}
	}
	//行求和
	vector<double> temrow;
	for (int i = 0; i < m.size(); i++)
	{
		double tem1 = 0;
		for (int j = 0; j < m.at(i).size(); j++)
		{
			tem1 += mtem.at(i).at(j);
		}
		temrow.push_back(tem1);
	}
	//归一化
	double tem2 = 0;
	for (int i = 0; i < temrow.size(); i++)
	{
		tem2 += temrow.at(i);
	}
	for (int i = 0; i < temrow.size(); i++)
	{
		temrow[i] = temrow.at(i) / tem2;
	}
	return temrow;
}

//二层矩阵和一层矩阵相乘
vector<double> TwoFlodMOneFlod(vector<vector<double>> w1, vector<double> w2)
{
	vector<double> res;
	for (int i = 0; i < w1.size(); i++)
	{
		double tem1 = 0;
		for (int j = 0; j < w1.at(i).size(); j++)
		{
			tem1 += w2.at(j) * w1.at(i).at(j);
		}
		res.push_back(tem1);
	}
	return res;
}

分别代表求特征矩阵和两个矩阵相乘

特殊

等到输入的时候直接傻眼了

这怎么有分数?我去,出题人想着逻辑太简单,考考你们的基础,我放几个分数在上面,整数和分数混合输入,傻*了吧

越想越气,这出题人真是个傻*

遂写了一组可以转化输入的函数

//将字符串的整数提取
double IntFromStr(string sastr)
{
	double sum = 0;
	for (int i = 0; i < sastr.size(); i++)
	{
		sum *= 10;
		sum += sastr.at(i) - '0';
	}
	return sum;
}

//接受整数和分数同时混合输入的函数
vector<double> GetInput()
{
	string str;
	getline(cin, str);
	vector<string> cutstr;
	int i = 0;
	while (i != -1)
	{
		i = str.find(' ');
		string tem(str, 0, i);
		str.erase(0, i + 1);
		cutstr.push_back(tem);
	}
	//cutstr.push_back(str);
	vector<double> res;
	for (int j = 0; j < cutstr.size(); j++)
	{
		int fl = cutstr.at(j).find("/");
		double tem2 = 0;
		if (fl == -1)
		{
			tem2 = IntFromStr(cutstr.at(j));
		}
		else
		{
			string tem4(cutstr.at(j), 0, fl);
			string tem5(cutstr.at(j), fl + 1, cutstr.size());
			tem2 = IntFromStr(tem4) / IntFromStr(tem5);
		}
		res.push_back(tem2);
	}
	return res;
}

具体的思路可以看上一篇文章 

代码

#include <iostream>
#include <vector>
#include <string>
#include <math.h>
#include <iomanip>

using namespace std;

double IntFromStr(string s)
{
	double n = 0;
	int size = s.size();
	double b = 0;
	int sign = 0;
	bool fr = 0, de = 0, in = 1;
	for (int i = 0; i < size; i++)
	{
		if (s[i] == '/')
		{
			sign = i;
			in = 0;
			fr = 1;
		}
		if (s[i] == '.')
		{
			sign = i;
			in = 0;
			de = 1;
		}
	}
	if (in == 1)
	{
		for (int i = 0; i < size; i++)
		{
			n += pow(10, size - 1 - i) * (int(s[i]) - int('0'));
		}
	}
	if (fr == 1)
	{
		for (int i = 0; i < sign; i++)
		{
			n += pow(10, sign - 1 - i) * (int(s[i]) - int('0'));
		}
		for (int i = sign + 1; i < size; i++)
		{
			b += pow(10, size - 1 - i) * (int(s[i]) - int('0'));
		}
		n /= b;
	}
	if (de == 1)
	{
		for (int i = 0; i < sign; i++)
		{
			n += pow(10, sign - 1 - i) * (int(s[i]) - int('0'));
		}
		for (int i = sign + 1; i < size; i++)
		{
			b += pow(10, size - 1 - i) * (int(s[i]) - int('0'));
		}
		n += b / pow(10, size - 1 - sign);
	}
	return n;
}

//接受整数和分数同时混合输入的函数
vector<double> GetInput()
{
	string str;
	getline(cin, str);
	vector<string> cutstr;
	int i = 0;
	while (i != -1)
	{
		i = str.find(' ');
		string tem(str, 0, i);
		str.erase(0, i + 1);
		cutstr.push_back(tem);
	}
	//cutstr.push_back(str);
	vector<double> res;
	for (int j = 0; j < cutstr.size(); j++)
	{
		double tem2 = IntFromStr(cutstr.at(j));
		res.push_back(tem2);
	}
	return res;
}

//计算特征向量
vector<double> ComputeCharacteristicVector(vector<vector<double>> m)
{
	//列向量归一化
	//建立临时阵,使其大小等于传入阵
	vector<vector<double>> mtem = m;
	for (int i = 0; i < m.at(0).size(); i++)
	{
		double sum = 0;
		for (int j = 0; j < m.size(); j++)
		{
			sum += m.at(j).at(i);
		}
		for (int j = 0; j < m.size(); j++)
		{
			mtem[j][i] = m.at(j).at(i) / sum;
		}
	}
	//行求和
	vector<double> temrow;
	for (int i = 0; i < m.size(); i++)
	{
		double tem1 = 0;
		for (int j = 0; j < m.at(i).size(); j++)
		{
			tem1 += mtem.at(i).at(j);
		}
		temrow.push_back(tem1);
	}
	//归一化
	double tem2 = 0;
	for (int i = 0; i < temrow.size(); i++)
	{
		tem2 += temrow.at(i);
	}
	for (int i = 0; i < temrow.size(); i++)
	{
		temrow[i] = temrow.at(i) / tem2;
	}
	return temrow;
}

//二层矩阵和一层矩阵相乘
vector<double> TwoFlodMOneFlod(vector<vector<double>> w1, vector<double> w2)
{
	vector<double> res;
	for (int i = 0; i < w1.size(); i++)
	{
		double tem1 = 0;
		for (int j = 0; j < w1.at(i).size(); j++)
		{
			tem1 += w2.at(j) * w1.at(i).at(j);
		}
		res.push_back(tem1);
	}
	return res;
}

int main()
{
	int n;
	cin >> n;
	cin.ignore(1000, '\n');

	vector<vector<double>> mat;
	for (int i = 0; i < n; i++)
	{
		vector<double> tem;
		for (int j = 0; j < n; j++)
		{
			string temstr;
			cin >> temstr;
			double tem0 = IntFromStr(temstr);
			tem.push_back(tem0);
		}
		mat.push_back(tem);
		
	}
	vector<double> characteristic1 = ComputeCharacteristicVector(mat);

	int m;
	cin >> m;
	cin.ignore(1000, '\n');
	vector<vector<double>> characteristic_vector_group;
	for (int i = 0; i < n; i++)
	{
		vector<vector<double>> tem3;
		for (int j = 0; j < m; j++)
		{
			vector<double> tem;
			for (int k = 0; k < m; k++)
			{
				string temstr;
				cin >> temstr;
				double tem0 = IntFromStr(temstr);
				tem.push_back(tem0);
			}
			tem3.push_back(tem);
		}
		characteristic_vector_group.push_back(ComputeCharacteristicVector(tem3));
	}

	//将第二次计算获得的矩阵处理成需要的样子
	vector<vector<double>> mat2;
	for (int i = 0; i < characteristic_vector_group.at(0).size(); i++)
	{
		vector<double> tem1;
		for (int j = 0; j < characteristic_vector_group.size(); j++)
		{
			tem1.push_back(characteristic_vector_group.at(j).at(i));
		}
		mat2.push_back(tem1);
	}

	vector<double> result = TwoFlodMOneFlod(mat2, characteristic1);

	for (auto i : result)
	{
		cout << fixed << setprecision(4) << i << " ";
	}

	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值