【算法】拍卖算法(最优分配问题)--启发式算法

问题描述

人对物品进行竞价,出价p,可卖出的价格w,收益profile = w - p
人:n1
物品:n2
对应关系:n1–>n2
目的:使最后所有人获得的总收益最大
更新价格公式:新价格 = (最大利润)-(次大利润)+ ε + 先前价格

竞价流程(哄抬物价p,并还要使总收益最大)

取 ε = 0.001,防止价格不上涨,导致死循环,价格从0开始

  1. 数据
    在这里插入图片描述
  2. 根据w,选择物品对其出价,价格p一般从0开始
    在这里插入图片描述
    依次对其出价,直到有冲突为止

在这里插入图片描述
4.
在这里插入图片描述
5.
在这里插入图片描述
6.
在这里插入图片描述

程序

// auction.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

/*
Maximilien Danisch
May 2017
http://bit.ly/maxdan94
maximilien.danisch@gmail.com

Info:
Feel free to use these lines as you wish. This is an efficient C implementation of the Auction algorithm for the assignement problem such as detailed in:
D.P. Bertsekas, A distributed algorithm for the assignment problem,Laboratory for Information and Decision Systems Working Paper (M.I.T., March 1979).

It should easily scale to hundreds of millions of nodes and/or edges if the data is not too adverserial.

To compile:
"gcc auction.c -O3 -o auction".

To execute:
"./auction edgelist.txt res.txt eps".
"edgelist.txt" should contain the edges with integral weights in the bipartite graph: one edge on each line separated by spaces "n1 n2 w", n1 for 0 to n1max and n2 for 0 to n2max.
"res.txt" contains the results: one edge "n1 n2 w" of the assignement on each line.
eps is the stepsize, if eps<1/min(n1,n2) then the algorithm is optimal.
Will print some information in the terminal.
*/

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdbool.h>
#include <fstream>
#include <math.h>

#define NLINKS 65536
using namespace std;
void CreatRandomEdge(char* filePath, int n1, int n2);

typedef struct {
	unsigned u;//first node
	unsigned v;//second node
	unsigned w;//weight of the edge
} edge;

typedef struct {

	//edge list
	unsigned n1;//number of nodes
	unsigned n2;//number of nodes
	unsigned e;//number of edges
	edge *edges;//list of edges

	bool b;//b=1 iff n1>n2
		   //graph
	unsigned *cd;//cumulative degree: (start with 0) length=dim+1
	unsigned *adj;//list of neighbors
	unsigned *w;//weight of the edges

} bipgraph;

void freebg(bipgraph *g) {
	free(g->edges);
	free(g->cd);
	free(g->adj);
	free(g->w);
	free(g);
}

//compute the maximum of two unsigned
inline unsigned max2u(unsigned a, unsigned b) {
	return (a>b) ? a : b;
}

//reading the edgelist of bipartit weighted graph from file
bipgraph* readedgelist(char* edgelist) {
	unsigned e1 = NLINKS;
	bipgraph *g = (bipgraph*)malloc(sizeof(bipgraph));
	FILE *file;

	g->n1 = 0;
	g->n2 = 0;
	g->e = 0;
	file = fopen(edgelist, "r");
	g->edges = (edge*)malloc(e1 * sizeof(edge));
	//e1 += NLINKS;
	//g->edges = (edge*)realloc(g->edges, e1 * sizeof(edge));
	while (fscanf(file, "%u %u %u\n", &(g->edges[g->e].u), &(g->edges[g->e].v), &(g->edges[g->e].w)) == 3) {
		g->n1 = max2u(g->n1, g->edges[g->e].u);
		g->n2 = max2u(g->n2, g->edges[g->e].v);
		if (g->e++ == e1) {
			e1 += NLINKS;
			g->edges = (edge*)realloc(g->edges, e1 * sizeof(edge));
		}
	}
	fclose(file);
	g->n1++;
	g->n2++;
	g->edges = (edge*)realloc(g->edges, g->e * sizeof(edge));
	return g;
}

//Building a special sparse graph structure
void mkbg(bipgraph *g) 
{
	unsigned int i, u;
	unsigned int *d;

	if (g->n1 <= g->n2) 
	{
		g->b = 0;
		d = (unsigned int*)calloc(g->n1, sizeof(unsigned));
		g->cd = (unsigned int*)malloc((g->n1 + 1) * sizeof(unsigned));
		g->adj = (unsigned int*)malloc((g->e) * sizeof(unsigned));
		g->w = (unsigned int*)malloc((g->e) * sizeof(unsigned));
		for (i = 0; i<g->e; i++) {
			d[g->edges[i].u]++;
		}
		g->cd[0] = 0;
		for (i = 1; i<g->n1 + 1; i++) {
			g->cd[i] = g->cd[i - 1] + d[i - 1];
			d[i - 1] = 0;
		}
		for (i = 0; i<g->e; i++) {
			u = g->edges[i].u;
			g->adj[g->cd[u] + d[u]] = g->edges[i].v;
			g->w[g->cd[u] + d[u]++] = g->edges[i].w;
		}
	}
	else 
	{
		g->b = 1;
		d = (unsigned int*)calloc(g->n2, sizeof(unsigned));
		g->cd = (unsigned int*)malloc((g->n2 + 1) * sizeof(unsigned));
		g->adj = (unsigned int*)malloc((g->e) * sizeof(unsigned));
		g->w = (unsigned int*)malloc((g->e) * sizeof(unsigned));

		//计算n2中每个节点有多少边
		for (i = 0; i<g->e; i++) {
			d[g->edges[i].v]++;
		}
		g->cd[0] = 0;
		for (i = 1; i<g->n2 + 1; i++) {
			g->cd[i] = g->cd[i - 1] + d[i - 1];
			d[i - 1] = 0;
		}
		for (i = 0; i<g->e; i++) {
			u = g->edges[i].v;
			g->adj[g->cd[u] + d[u]] = g->edges[i].u;
			g->w[g->cd[u] + d[u]++] = g->edges[i].w;
		}
		i = g->n1;
		g->n1 = g->n2;
		g->n2 = i;
	}
	free(d);
	free(g->edges);
}

//bidding towards convergence
unsigned bidding(bipgraph *g, double eps) 
{
	unsigned u, v, w, i, j, k, res;
	double *p = (double*)calloc(g->n2, sizeof(double));//p[i]=price of object i
	unsigned *a = (unsigned int*)malloc(g->n2 * sizeof(unsigned));//a[target]=-1 if not assigned = source if assigned
	unsigned *aw = (unsigned int*)malloc(g->n2 * sizeof(unsigned));//aw[target]=? if not assigned = weigth of edge source-target if assigned
	for (v = 0; v<g->n2; v++) {
		a[v] = -1;
	}
	//set data structure
	unsigned n_set = g->n1;//
	unsigned *l_set = (unsigned int*)malloc(g->n1 * sizeof(unsigned));//
													   //bool *t_set=malloc(g->n1*sizeof(bool));//
	for (u = 0; u<n_set; u++) {
		l_set[u] = u;
		//t_set[u]=1;
	}

	//double eps=0.1;//1./((double)(g->n1)+1.);///
	double max, max2;
	unsigned wmax;

	res = 0;
	while (n_set>0) 
	{
		u = l_set[n_set - 1];
		//printf("n_set, u, w = %u, %u, %u\n",n_set,u,res);

		//找权重最大的一个u(火力点)
		max = 0;
		for (i = g->cd[u]; i<g->cd[u + 1]; i++) {
			v = g->adj[i];
			w = g->w[i];
			//printf("w=%u\n",w);
			if ((double)w - p[v]>max) {
				max = (double)w - p[v];
				wmax = w;
				k = v;
			}
		}
		//printf("max=%f\n",max);
		if (max == 0) {
			n_set--;
			continue;
		}

		//找次大的一个u(火力点)
		max2 = 0;
		for (i = g->cd[u]; i<g->cd[u + 1]; i++) {
			v = g->adj[i];
			if (v != k) {
				w = g->w[i];
				if ((double)w - p[v]>max2) {
					max2 = (double)w - p[v];
				}
			}
		}

		//printf("max2=%f\n",max2);
		p[k] += max - max2 + eps;
		//printf("k=%u\n",k);
		//printf("p[k]=%f\n",p[k]);
		if (a[k] != -1) {
			l_set[n_set - 1] = a[k];
			res -= aw[k];
		}
		else {
			n_set--;
		}
		a[k] = u;
		aw[k] = wmax;
		res += wmax;
	}

	g->edges = (edge*)malloc(g->n1 * sizeof(edge));
	j = 0;
	for (i = 0; i<g->n2; i++) {
		if (a[i] != -1) {
			g->edges[j].u = a[i];
			g->edges[j].v = i;
			g->edges[j++].w = aw[i];
		}
	}
	g->edges = (edge*)realloc(g->edges, j * sizeof(edge));
	g->e = j;
	return res;
}

void printres(bipgraph *g, char *output) {
	unsigned i;
	edge ed;
	FILE* file = fopen(output, "w");
	if (g->b) {
		for (i = 0; i<g->e; i++) {
			ed = g->edges[i];
			fprintf(file, "%u %u %u\n", ed.v, ed.u, ed.w);
		}
	}
	else {
		for (i = 0; i<g->e; i++) {
			ed = g->edges[i];
			fprintf(file, "%u %u %u\n", ed.u, ed.v, ed.w);
		}
	}
	fclose(file);
}


//int main(int argc, char** argv) 
int main(void) 
{
	bipgraph* g;
	unsigned w;
	time_t t0, t1, t2;

	char* argv[4];
	
	argv[1] = "D:\\testspace\\拍卖算法\\auction\\testEdgesList.txt";
	argv[2] = "D:\\testspace\\拍卖算法\\auction\\testRes.txt";
	argv[3] = "0.01";
	argv[5] = "6";
	argv[6] = "6";
	int n1 = atoi(argv[5]);
	int n2 = atoi(argv[6]);
	CreatRandomEdge(argv[1], n1, n2);


	double eps = atof(argv[3]);
	t1 = time(NULL);
	t0 = t1;

	printf("Reading edgelist from file %s\n", argv[1]);
	g = readedgelist(argv[1]);
	printf("Number of left nodes: %u\n", g->n1);
	printf("Number of right nodes: %u\n", g->n2);
	printf("Number of edges: %u\n", g->e);

	t2 = time(NULL);
	printf("- Time = %ldh%ldm%lds\n", (t2 - t1) / 3600, ((t2 - t1) % 3600) / 60, ((t2 - t1) % 60));
	t1 = t2;

	printf("Building datastructure\n");

	mkbg(g);
	t2 = time(NULL);
	printf("- Time = %ldh%ldm%lds\n", (t2 - t1) / 3600, ((t2 - t1) % 3600) / 60, ((t2 - t1) % 60));
	t1 = t2;

	printf("Computing optimal assignment\n");

	w = bidding(g, eps);

	printf("optimal assignment value = %u\n", w);

	t2 = time(NULL);
	printf("- Time = %ldh%ldm%lds\n", (t2 - t1) / 3600, ((t2 - t1) % 3600) / 60, ((t2 - t1) % 60));
	t1 = t2;

	printf("Writting the results in file %s\n", argv[2]);
	printres(g, argv[2]);
	freebg(g);

	t2 = time(NULL);
	printf("- Time = %ldh%ldm%lds\n", (t2 - t1) / 3600, ((t2 - t1) % 3600) / 60, ((t2 - t1) % 60));
	t1 = t2;

	printf("- Overall time = %ldh%ldm%lds\n", (t2 - t0) / 3600, ((t2 - t0) % 3600) / 60, ((t2 - t0) % 60));

	return 0;
}

void CreatRandomEdge(char* filePath, int n1, int n2)
{
	ofstream fout;
	fout.open(filePath);
	int edgesNum = n1 * n2;

	int pI = n1 - 1;//人索引
	for (int i = 0; i < n1; i++)
	{	
		for (int j = 0; j < n2; j++)
		{
			fout << pI << " " << j << " " << (rand() % edgesNum)
				<< "\n";
		}
		pI--;
	}
	fout.close();
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值